Thời gian đo lường và điểm chuẩn cho các phương pháp Ruby


88

Làm cách nào để đo thời gian thực hiện bởi một phương thức và các câu lệnh riêng lẻ trong phương thức đó trong Ruby. Nếu bạn thấy phương pháp dưới đây, tôi muốn đo tổng thời gian thực hiện theo phương pháp và thời gian thực hiện để truy cập cơ sở dữ liệu và truy cập redis. Tôi không muốn viết Benchmark.measure trước mỗi câu lệnh. Trình thông dịch ruby ​​có cung cấp cho chúng ta bất kỳ điểm hấp dẫn nào để thực hiện việc này không?

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

có một cái gì đó tương tự như new Date()javascript mà ruby ​​có, nhưng tôi không thể nhớ cú pháp chính xác. nên cung cấp cho bạn một phong nha google niêm yết mặc dù
reagan

1
@Phani Bạn có thể chọn một câu trả lời đúng không? Sau 8 năm, tôi nghĩ rằng có một số câu trả lời chắc chắn ở đây. Cảm ơn.
Joshua Pinter

Câu trả lời:


113

Bạn có thể sử dụng Timeđối tượng. ( Tài liệu thời gian )

Ví dụ,

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

diff = finish - start

diff sẽ tính bằng giây, dưới dạng số dấu phẩy động.

EDIT: endđược bảo lưu.


13
chỉ là một chỉnh sửa nhỏ. endđược dành riêng, vì vậy hãy sử dụng một số tên biến khác.
Jason Kim

4
Time.nowbị ảnh hưởng bởi các điều chỉnh đối với đồng hồ hệ thống, vì vậy cách tốt nhất là sử dụng Process.clock_gettime(Process::CLOCK_MONOTONIC)thay thế. Nhưng đối với những tính toán thô thì điều này không thành vấn đề. blog.dnsimple.com/2018/03/elapsed-time-with-ruby-the-right-way
Patrick Brinich-Langlois 21/02/19

104

Cách đơn giản nhất:

require 'benchmark'

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

Đầu ra mẫu:

2.2.3 :001 > foo
  5.230000   0.020000   5.250000 (  5.274806)

Các giá trị là: thời gian cpu, thời gian hệ thống, tổng và thời gian thực đã trôi qua.

Nguồn: ruby docs .


40
Bạn cũng có thể làm Benchmark.realtime { block }nếu bạn chỉ muốn thời gian thực
jmccure

35

Sử dụng BenchmarkBáo cáo của

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

Điều này sẽ xuất ra một cái gì đó như sau:

                        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.

Thông tin thêm có thể được tìm thấy ở đây .


2
Tôi vừa quay lại câu trả lời của riêng mình và rất ấn tượng (một lần nữa) với cách Benchmark xử lý điều này. Yêu Ruby.
Joshua Pinter

2
Đây nên là câu trả lời ưa thích: Bởi vì, kể từ Ruby 2.2, Benchmarklớp sử dụng một đồng hồ đơn điệu, như đã thảo luận trong các câu trả lời khác. Ví dụ: xem mã nguồn sau và tìm "thước đo độ phân giải" trên dòng 286: github.com/ruby/ruby/blob/ruby_2_2/lib/benchmark.rb
Purplejacket

17

Nhiều câu trả lời gợi ý việc sử dụng Time.now. Nhưng nó là giá trị nhận thức rằng Time.nowcó thể thay đổi. Đồng hồ hệ thống có thể bị trôi và có thể được sửa bởi quản trị viên của hệ thống hoặc thông qua NTP. Do đó, Time.now có thể nhảy tới hoặc lùi lại và đưa ra kết quả không chính xác cho điểm chuẩn của bạn.

Một giải pháp tốt hơn là sử dụng đồng hồ đơn âm của hệ điều hành, đồng hồ này luôn chuyển động về phía trước. Ruby 2.1 trở lên cấp quyền truy cập vào điều này thông qua:

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

Bạn có thể đọc thêm chi tiết tại đây . Ngoài ra, bạn có thể thấy dự án Ruby nổi tiếng, Sidekiq, đã chuyển sang đồng hồ đơn sắc .


7

Một suy nghĩ thứ hai, xác định hàm đo () với đối số khối mã Ruby có thể giúp đơn giản hóa mã đo thời gian:

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

Trong định nghĩa của bạn, bạn gọi nó benchmark. Khi bạn sử dụng nó được gọi measure. Hãy sửa lỗi này.
Sandro L

4

Theo tinh thần câu trả lời của wquist , nhưng đơn giản hơn một chút, bạn cũng có thể làm như dưới đây:

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

Câu trả lời này là một cách (hơi) khác để trả lời câu hỏi. Chỉ vì bạn có thể tìm ra nó từ câu trả lời của @ wquist không có nghĩa là nó không hợp lệ.
thesecretmaster,

3

Nhìn vào ruby-prof gói, nó sẽ có những gì bạn cần. Nó sẽ tạo ra các ngăn xếp cuộc gọi khổng lồ với thời gian.

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

Nó có thể quá chi tiết, trong trường hợp đó, chỉ gói các phần lớn hơn vào Benchmark.measurecó thể là một cách tốt để thực hiện.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.