Ruby Yöntemleri için Ölçme ve Karşılaştırma Süresi


90

Ruby'de bir yöntem tarafından harcanan zamanı ve bu yöntemdeki bireysel ifadeleri nasıl ölçebilirim? Aşağıdaki yöntemi görürseniz, yöntemin harcadığı toplam süreyi ve veritabanı erişimi ve redis erişimi için harcanan zamanı ölçmek istiyorum. Her ifadeden önce Benchmark.measure yazmak istemiyorum. Ruby tercümanı bunu yapmamız için bize herhangi bir kanca veriyor mu?

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

new Date()Ruby'de javascript'e benzer bir şey var, ancak doğru sözdizimini hatırlayamıyorum. size düzgün bir Google listesi vermeli
reagan

1
@Phani Lütfen doğru cevabı seçer misiniz? 8 yılın ardından, burada bazı sağlam cevaplar olduğunu düşünüyorum. Teşekkürler.
Joshua Pinter

Yanıtlar:


118

TimeNesneyi kullanabilirsin . ( Zaman Belgeleri )

Örneğin,

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

diff = finish - start

diff saniye cinsinden kayan nokta sayısı olarak olacaktır.

EDIT: endsaklıdır.


14
sadece küçük bir düzeltme. endayrılmıştır, bu nedenle başka bir değişken adı kullanın.
Jason Kim

5
Time.nowsistem saatindeki ayarlamalardan etkilenir, bu nedenle bunun Process.clock_gettime(Process::CLOCK_MONOTONIC)yerine kullanılması en iyi uygulamadır . Ancak kaba hesaplamalar için bu önemli değil. blog.dnsimple.com/2018/03/elapsed-time-with-ruby-the-right-way
Patrick Brinich-Langlois

105

En basit yol:

require 'benchmark'

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

Örnek çıktı:

2.2.3 :001 > foo
  5.230000   0.020000   5.250000 (  5.274806)

Değerler şunlardır: cpu zamanı, sistem zamanı, toplam ve gerçek geçen süre.

Kaynak: ruby docs .


41
Benchmark.realtime { block }Sadece gerçek zamanlı istiyorsanız da yapabilirsiniz
jmccure

36

BenchmarkRaporunu Kullan

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

Bu, aşağıdaki gibi bir sonuç verecektir:

                        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.

Daha fazla bilgiyi burada bulabilirsiniz .


2
Kendi cevabıma geri döndüm ve Benchmark'ın bunu nasıl ele aldığından (yine) etkilendim. Ruby'yi seviyorum.
Joshua Pinter

2
Bu tercih edilen cevap olmalıdır: Çünkü, Ruby 2.2'den itibaren, Benchmarksınıf diğer cevaplarda tartışıldığı gibi tekdüze bir saat kullanır. Örneğin aşağıdaki kaynak koduna bakın ve 286. satırda "def measure" arayın
Purplejacket

19

Cevapların birçoğu, kullanımını öneriyor Time.now. Ancak Time.nowdeğişebileceğinin farkında olmaya değer . Sistem saatleri kayabilir ve sistem yöneticisi tarafından veya NTP aracılığıyla düzeltilebilir. Bu nedenle Time.now'un ileri veya geri atlaması ve kıyaslamanıza hatalı sonuçlar vermesi mümkündür.

Daha iyi bir çözüm, işletim sisteminin her zaman ilerleyen monoton saatini kullanmaktır. Ruby 2.1 ve üzeri, buna şu yolla erişim sağlar:

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

Daha fazla ayrıntıyı buradan okuyabilirsiniz . Ayrıca popüler Ruby projesi Sidekiq'in monoton saate geçiş yaptığını görebilirsiniz .


7

İkinci bir düşünce, measure () işlevini Ruby kod bloğu argümanı ile tanımlamak , zaman ölçüm kodunu basitleştirmeye yardımcı olabilir:

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

Tanımınıza göre onu adlandırıyorsunuz benchmark. Onu kullandığınızda denir measure. Lütfen bunu düzeltin.
Sandro L

4

Wquist'in cevabı ruhuna göre , ancak biraz daha basit, aşağıdaki gibi de yapabilirsiniz:

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

Bu cevap, soruyu cevaplamanın (biraz) farklı bir yoludur. Bunu @ wquist'in cevabından anlayabilmeniz, geçerli olmadığı anlamına gelmez.
thesecretmaster

3

İçine bak ruby-profpakette, ne gerek olmalıdır. Zamanlamalarla büyük çağrı yığınları oluşturacaktır.

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

Çok ayrıntılı olabilir, bu durumda daha büyük bölümleri sarmak Benchmark.measureiyi bir yol olabilir.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.