برنامه نویسی

معیار IT: تصمیمات بهینه سازی بر اساس داده های واقعی و نه لرزش

عملکرد کد ما چیزی است که همه ما باید به عنوان توسعه دهندگان به آن اهمیت دهیم. ما همیشه باید در تلاش باشیم تا کد خود را به همان سرعت و به همان اندازه کارآمد انجام دهیم. اما این سؤال را ایجاد می کند ، چگونه می توانیم به طور عینی کد خود را اندازه گیری کنیم؟

به جای اینکه حدس بزنیم که چه عملی را صرفاً بر اساس لرزش در نظر می گیریم ، معیار می تواند داده های تجربی را به ما بدهد تا بتوانیم تصمیمات خوبی بگیریم. به طور خاص ، ما می خواهیم این کار را انجام دهیم که مسیرهای کد را بهینه می کنیم ، رویکردهای مختلف را مقایسه می کنیم و کتابخانه های شخص ثالث را ارزیابی می کنیم.

ما نمی توانیم به غرایز و لرزش خود اعتماد کنیم تا مشخص کنیم کد ما چقدر خوب است ، ما به داده نیاز داریم. روبی یک کتابخانه برای آن دارد.

شروع

ما قصد داریم از کتابخانه معیار استفاده کنیم که بخشی از کتابخانه استاندارد روبی است. ما با نیاز به آن شروع می کنیمبشر

require 'benchmark'
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

اولین کاری که ما می خواهیم انجام دهیم این است که اندازه گیری کنید که چه مدت طول می کشد تا مجموعه ای از یک میلیون عنصر ایجاد شود.

require 'benchmark'

time = Benchmark.measure do
  array = Array.new(1_000_000) do |i| 
      i 
  end
end

puts time
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

ما خروجی دریافت خواهیم کرد که به نظر می رسد:

0.024869   0.000951   0.025820 (  0.025847)
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این اعداد از راست به چپ نشان می دهد:

  • زمان پردازنده کاربر
  • زمان پردازنده سیستم
  • کل زمان پردازنده (زمان پردازنده کاربر + زمان پردازنده سیستم)
  • زمان سپری شده واقعی – این در پرانتز است.

زمان سپری شده واقعی همان چیزی است که ما به آن علاقه مند هستیم زیرا این چیزی را که کاربران تجربه می کنند نشان می دهد. زمان CPU کاربر زمان صرف شده توسط رایانه است که کد ما را در حالت کاربر اجرا می کند ، یعنی کد یاقوت که ما نوشتیم ، چیزهای کتابخانه استاندارد روبی ، کد در هر سنگهای قیمتی که ما استفاده می کنیم و مترجم روبی است. زمان پردازنده سیستم موارد پایین تر از سطح پایین مانند همه کارهایی است که سیستم عامل ما مطابق درخواست Ruby ما انجام می دهد ، مانند عملیات فایل ، تخصیص حافظه و مدیریت و غیره.

عکس توسط گیلبرتو اولیمپیو / Unsplash

من زیباتر می خواهم!

مسلماً ، این خروجی به راحتی قابل خواندن نیست. بنابراین ما می توانیم چیزها را به سطح بعدی برسانیم. ما می توانیم از Benchmark.bm برای ایجاد نتیجه بسیار خواندنی استفاده کنیم و به ما اجازه می دهیم رویکردهای الگوریتمی را در برابر یکدیگر مقایسه کنیم.

این کد همان کار را انجام می دهد – مجموعه ای از یک میلیون عنصر را ایجاد کنید ، اما این کار را با استفاده از سه رویکرد مختلف انجام می دهد و سپس گزارشی را به ما می دهد که به ما امکان می دهد تا تعیین کنیم که کدام روش بهترین است. می خواهم توجه داشته باشم که 10 مورد به روش #BM منتقل می شود ، عرض هر ستون را مشخص می کند. شما می توانید آن را بر روی هر چیز دیگری تنظیم کنید ، ما فقط از 10 استفاده می کنیم زیرا این در اینجا متناسب با اهداف ما است.

require 'benchmark'

n = 1_000_000

Benchmark.bm(10) do |x|
  x.report("Array.new:") { Array.new(n) { |i| i } }
  x.report("Range:") { (0...n).to_a }
  x.report("upto:") { 
    array = []
    0.upto(n-1) { |i| array << i }
    array
  }
end
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در حال اجرا که ما خروجی مشابه این را دریافت می کنیم:

                 user     system      total        real
Array.new:   0.024696   0.000604   0.025300 (  0.025357)
Range:       0.011129   0.001368   0.012497 (  0.012498)
upto:        0.027432   0.001566   0.028998 (  0.029064)
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

فقط با نگاهی به این امر ، می توانیم بگوییم که استفاده از رویکرد دامنه سریعترین است.

آن را گرم کنید

نکته مهمی که باید از آن آگاه باشیم این است که وقتی در روبی معیار می شویم ، گاهی اوقات ، اولین اجرای کمی از کد متفاوت از اجراهای بعدی عمل می کند. برای پرداختن به این موضوع ، ما روش #BMBM بسیار خلاقانه ای داریم. این کار این است که کد شما را دو بار اجرا می کند. اولین بار به منظور گرم کردن کارها و بار دوم این کار را برای واقعیت ها انجام می دهد. این داده ها را برای هر دو فراهم می کند تا بتوانید تعیین کنید که آیا نوعی تأثیر وجود داشته است یا خیر.

بیایید به یک مثال نگاه کنیم. ما قصد داریم یک آرایه بزرگ ایجاد کنیم و مواردی را برای آن انجام دهیم:

require 'benchmark'

array = (1..1_000_000).to_a
sorted = array.dup
reversed = array.reverse

Benchmark.bmbm(7) do |x|
  x.report("sort:") { array.dup.sort }
  x.report("sort!:") { sorted.dup.sort! }
  x.report("reverse:") { reversed.dup.sort }
end
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

با اجرای این کار ، ما این نتیجه را می گیریم:

Rehearsal --------------------------------------------
sort:      0.005534   0.001237   0.006771 (  0.006823)
sort!:     0.005565   0.001304   0.006869 (  0.006881)
reverse:   0.027210   0.001318   0.028528 (  0.028594)
----------------------------------- total: 0.042168sec

               user     system      total        real
sort:      0.005511   0.001054   0.006565 (  0.006577)
sort!:     0.005554   0.001061   0.006615 (  0.006617)
reverse:   0.026982   0.001266   0.028248 (  0.028336)
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

کد به شما می گوید که تمرین چه مدت طول کشید. می توانیم ببینیم که همه چیز فقط کمی سریعتر اجرا می شود.

اما آیا این مقیاس است؟

ما می توانیم از این کتابخانه برای ایجاد گزارشی استفاده کنیم تا در صورت اندازه گیری کد ما به ما نشان دهد.

این کمی از کد کدی را که ما چهار بار با اندازه های مختلف آزمایش می کنیم ، اجرا می کند تا ببیند که چگونه بر اساس میزان داده هایی که باید با آن سروکار داشته باشد ، عملکرد آن را انجام می دهد.

require 'benchmark'

sizes = [50_000, 100_000, 500_000, 1_000_000]

Benchmark.benchmark(Benchmark::CAPTION, 15, Benchmark::FORMAT, ">total:", ">avg:") do |x|
  results = sizes.map do |size|
    x.report("Array(#{size}):") do
      Array.new(size) { |i| i }
    end
  end

  sum = results.inject(:+)

  [sum, sum / results.size]
end
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

این نتایج حاصل از آن است:

                      user     system      total        real
Array(50000):     0.001398   0.000038   0.001436 (  0.001462)
Array(100000):    0.002823   0.000114   0.002937 (  0.002938)
Array(500000):    0.014158   0.000335   0.014493 (  0.014605)
Array(1000000):   0.028183   0.000675   0.028858 (  0.028969)
>total:           0.046562   0.001162   0.047724 (  0.047974)
>avg:             0.011640   0.000291   0.011931 (  0.011994)
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

پایان

شما باید کد خود را معیار کنید ، و گرچه ابزارهای دیگری برای آن وجود دارد ، روبی یکی از آنها را در کتابخانه استاندارد خود به شما می دهد. با این دانش می توانیم اطمینان حاصل کنیم که ما در حال تصمیم گیری بهینه سازی بر اساس داده های واقعی هستیم و نه لرزش و ما می توانیم پیامدهای عملکرد رویکردهای مختلف الگوریتمی را درک کنیم.

با این حال ، به یاد داشته باشید که عملکرد تنها یک بعد کد خوب است. خوانایی و حفظ قابلیت اطمینان به طور کلی بسیار مهمتر است. سریعترین کد همیشه بهترین انتخاب نیست.

این وبلاگ توسط مربی تورینگ ، مایک دائو نوشته شده است.

حتماً ما را در اینستاگرام ، X و LinkedIn -turing_school دنبال کنید

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا