Виміряти і порівняти час для методів Ruby


87

Як я можу виміряти час, зайнятий методом, та окремі твердження в цьому методі в Ruby. Якщо ви бачите наведений нижче метод, я хочу виміряти загальний час, зайнятий методом, і час, необхідний для доступу до бази даних та доступу до повторного використання. Я не хочу писати Benchmark.measure перед кожним твердженням. Чи дає нам інтерпретатор рубінів якісь гачки для цього?

def foo
# code to access database
# code to access redis. 
end

є щось подібне до new Date()javascript, яке має ruby, але я не пам’ятаю правильний синтаксис. повинен дати вам пристойний список у Google, хоча
Рейган

1
@Phani Чи можете ви вибрати правильну відповідь? Після 8 років, я думаю, тут є кілька вагомих відповідей. Дякую.
Джошуа Пінтер,

Відповіді:


112

Ви можете використовувати Timeоб'єкт. ( Часові документи )

Наприклад,

start = Time.now
# code to time
finish = Time.now

diff = finish - start

diff буде в секундах, як число з плаваючою комою.

EDIT: endзарезервовано.


13
просто незначна корекція. endзарезервовано, тому використовуйте інше ім'я змінної.
Джейсон Кім,

4
Time.nowна це впливають налаштування системного годинника, тому найкраще використовувати його Process.clock_gettime(Process::CLOCK_MONOTONIC)замість. Але для грубих розрахунків це не має значення. blog.dnsimple.com/2018/03/elapsed-time-with-ruby-the-right-way
Патрік Брініч-Ланглуа

102

Найпростіший спосіб:

require 'benchmark'

def foo
 time = Benchmark.measure {
  code to test
 }
 puts time.real #or save it to logs
end

Вихідні дані:

2.2.3 :001 > foo
  5.230000   0.020000   5.250000 (  5.274806)

Значення: час процесора, системний час, загальний та реальний минулий час.

Джерело: ruby docs .


40
Ви також можете зробити, Benchmark.realtime { block }якщо хочете просто в режимі реального часу
jmccure

35

Використовуйте BenchmarkЗвіт

require 'benchmark' # Might be necessary.

def foo
  Benchmark.bm( 20 ) do |bm|  # The 20 is the width of the first column in the output.
    bm.report( "Access Database:" ) do 
      # Code to access database.
    end
   
    bm.report( "Access Redis:" ) do
      # Code to access redis.
    end
  end
end

Це виведе щось на зразок наступного:

                        user     system      total        real
Access Database:    0.020000   0.000000   0.020000 (  0.475375)
Access Redis:       0.000000   0.000000   0.000000 (  0.000037)

<------ 20 -------> # This is where the 20 comes in. NOTE: This is not shown in output.

Більше інформації можна знайти тут .


2
Я щойно повернувся до власної відповіді і був вражений (знову ж таки) тим, як Benchmark з цим справляється. Люблю Рубі.
Джошуа Пінтер

2
Це має бути найкращою відповіддю: оскільки, станом на Ruby 2.2, Benchmarkклас використовує монотонні годинники, як обговорювалося в інших відповідях. Дивіться, наприклад, наступний вихідний код, і шукайте "міра захисту" у рядку 286: github.com/ruby/ruby/blob/ruby_2_2/lib/benchmark.rb
Purplejacket

17

Багато відповідей пропонують використовувати Time.now. Але варто знати, що Time.nowможе змінитися. Системні годинники можуть дрейфувати і можуть бути виправлені адміністратором системи або через NTP. Отже, Time.now може стрибати вперед або назад і давати вашим тестам неточні результати.

Краще рішення - використовувати монотонний годинник операційної системи, який завжди рухається вперед. Рубін 2.1 і вище надає доступ до цього через:

start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
# code to time
finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
diff = finish - start # gets time is seconds as a float

Детальніше ви можете прочитати тут . Також ви можете побачити популярний проект Ruby, Sidekiq, який перейшов на монотонні годинники .


7

Друга думка - визначити функцію measure () за допомогою аргументу блоку коду Ruby може допомогти спростити код часової міри:

def measure(&block)
  start = Time.now
  block.call
  Time.now - start
end

# t1 and t2 is the executing time for the code blocks.
t1 = measure { sleep(1) }

t2 = measure do
  sleep(2)
end

У своєму визначенні ви це називаєте benchmark. Коли ви використовуєте це, воно називається measure. Будь ласка, виправте це.
Сандро Л

4

У дусі відповіді вікіста , але трохи простіше, ви також можете зробити це, як показано нижче:

start = Time.now
# code to time
Time.now - start

Ця відповідь - (трохи) інший спосіб відповісти на питання. Те, що ви могли зрозуміти це з відповіді @ wquist, не означає, що воно не є дійсним.
thesecretmaster

3

Загляньте в ruby-profупаковку, там має бути те, що вам потрібно. Це створить величезні стеки дзвінків із синхронізацією.

http://ruby-prof.rubyforge.org/

Це може бути занадто детально, і в цьому випадку Benchmark.measureможе бути гарним способом просто обернути більші розділи .


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.