การวัดและเวลามาตรฐานสำหรับวิธี Ruby


90

ฉันจะวัดเวลาที่ใช้โดยวิธีการและข้อความแต่ละรายการในวิธีนั้นใน Ruby ได้อย่างไร หากคุณเห็นวิธีการด้านล่างฉันต้องการวัดเวลาทั้งหมดที่ใช้โดยวิธีการและเวลาที่ใช้ในการเข้าถึงฐานข้อมูลและการเข้าถึงซ้ำ ฉันไม่ต้องการเขียน Benchmark.measure ก่อนทุกคำสั่ง ล่ามทับทิมให้ตะขอสำหรับทำสิ่งนี้แก่เราหรือไม่?

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

มีบางอย่างที่คล้ายกับnew Date()จาวาสคริปต์ที่ทับทิมมี แต่ฉันจำไวยากรณ์ที่ถูกต้องไม่ได้ ควรให้รายชื่อ Google ที่ดีแก่คุณ
reagan

1
@Phani กรุณาเลือกคำตอบที่ถูกต้องได้ไหม หลังจากผ่านไป 8 ปีฉันคิดว่ามีคำตอบที่ชัดเจนที่นี่ ขอบคุณ.
Joshua Pinter

คำตอบ:


118

คุณสามารถใช้Timeวัตถุ ( เอกสารเวลา )

ตัวอย่างเช่น,

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

diff = finish - start

diff จะเป็นหน่วยเป็นวินาทีเป็นตัวเลขทศนิยม

แก้ไข: endสงวนไว้


14
เพียงการแก้ไขเล็กน้อย endสงวนไว้ดังนั้นให้ใช้ชื่อตัวแปรอื่น
Jason Kim

5
Time.nowได้รับผลกระทบจากการปรับนาฬิการะบบดังนั้นจึงควรใช้แนวทางปฏิบัติที่ดีที่สุดProcess.clock_gettime(Process::CLOCK_MONOTONIC)แทน แต่สำหรับการคำนวณคร่าวๆสิ่งนี้ไม่สำคัญ blog.dnsimple.com/2018/03/elapsed-time-with-ruby-the-right-way
Patrick Brinich-Langlois

105

วิธีที่ง่ายที่สุด:

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 .


41
คุณสามารถทำได้Benchmark.realtime { block }หากต้องการเรียลไทม์
jmccure

36

ใช้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 จัดการเรื่องนี้ รักทับทิม
Joshua Pinter

2
นี่ควรเป็นคำตอบที่ต้องการ: เนื่องจากใน Ruby 2.2 Benchmarkคลาสนี้ใช้นาฬิกาแบบโมโนโทนิคตามที่กล่าวไว้ในคำตอบอื่น ๆ ดูตัวอย่างเช่นซอร์สโค้ดต่อไปนี้และมองหา "def measure" ในบรรทัด 286: github.com/ruby/ruby/blob/ruby_2_2/lib/benchmark.rb
Purplejacket

19

Time.nowหลายคำตอบแนะนำการใช้งานของ แต่มันก็คุ้มค่าที่จะตระหนักว่าTime.nowสามารถเปลี่ยนแปลงได้ นาฬิการะบบสามารถลอยและอาจได้รับการแก้ไขโดยผู้ดูแลระบบหรือผ่าน NTP ดังนั้นจึงเป็นไปได้ที่ Time.now จะกระโดดไปข้างหน้าหรือถอยหลังและให้ผลลัพธ์ที่ไม่ถูกต้องในการเปรียบเทียบของคุณ

ทางออกที่ดีกว่าคือใช้ monotonic clock ของระบบปฏิบัติการซึ่งมักจะก้าวไปข้างหน้า Ruby 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เมื่อคุณใช้มันก็จะเรียกว่า โปรดแก้ไขปัญหานี้
Sandro L

4

ด้วยจิตวิญญาณของคำตอบของ wquistแต่ง่ายกว่าเล็กน้อยคุณสามารถทำได้ดังนี้:

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

คำตอบนี้เป็นวิธี (เล็กน้อย) ในการตอบคำถาม เพียงเพราะคุณสามารถคิดออกจากคำตอบของ @ wquist ไม่ได้หมายความว่ามันไม่ถูกต้อง
thesecretmaster

3

ดูในruby-profแพคเกจมันควรมีสิ่งที่คุณต้องการ มันจะสร้างกองการโทรขนาดใหญ่พร้อมการกำหนดเวลา

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

มันอาจจะละเอียดเกินไปซึ่งในกรณีนี้การตัดส่วนที่ใหญ่กว่าเข้ามาBenchmark.measureอาจเป็นวิธีที่ดี


0

อีกวิธีหนึ่งในการเปรียบเทียบโค้ดโดยอัตโนมัติในคอนโซลรางคือการใช้อัญมณีนี้: https://github.com/igorkasyanchuk/execution_time

คุณจะเห็นข้อมูลที่คล้ายกันตามที่คุณได้รับจากคำขอในบันทึก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.