Ruby 方法的测量和基准时间

Posted

技术标签:

【中文标题】Ruby 方法的测量和基准时间【英文标题】:Measure and Benchmark Time for Ruby Methods 【发布时间】:2012-07-09 12:31:39 【问题描述】:

如何在 Ruby 中测量一个方法和该方法中的各个语句所花费的时间。如果您看到下面的方法,我想测量该方法所花费的总时间以及数据库访问和 redis 访问所花费的时间。我不想在每个陈述之前都写 Benchmark.measure。 ruby 解释器是否为我们提供了执行此操作的任何钩子?

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

【问题讨论】:

有一些类似于 ruby​​ 的 new Date() 的东西,但我不记得正确的语法。不过应该给你一个不错的谷歌列表 @Phani 你能选择一个正确的答案吗? 8年后,我认为这里有一些可靠的答案。谢谢。 【参考方案1】:

最简单的方法:

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)

值是:cpu 时间、系统时间、总和实际运行时间。

来源:ruby docs。

【讨论】:

如果你只是想要实时,你也可以Benchmark.realtime block 【参考方案2】:

您可以使用Time 对象。 (Time Docs)

例如,

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

diff = finish - start

diff 以秒为单位,为浮点数。

编辑:end 已保留。

【讨论】:

只是一个小修正。 end 是保留的,所以使用其他变量名。 Time.now 会受到系统时钟调整的影响,因此最好改用Process.clock_gettime(Process::CLOCK_MONOTONIC)。但是对于粗略的计算,这并不重要。 blog.dnsimple.com/2018/03/elapsed-time-with-ruby-the-right-way【参考方案3】:

使用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.

更多信息可以在here找到。

【讨论】:

我刚刚回到自己的答案,并(再次)对 Benchmark 处理此问题的方式印象深刻。爱红宝石。 这应该是首选答案:因为从 Ruby 2.2 开始,Benchmark 类使用单调时钟,如其他答案中所述。例如,请参阅以下源代码,并在第 286 行查找“def measure”:github.com/ruby/ruby/blob/ruby_2_2/lib/benchmark.rb【参考方案4】:

许多答案建议使用Time.now。但值得注意的是Time.now 可以更改。系统时钟可能会漂移,并可能由系统管理员或通过 NTP 进行更正。因此,Time.now 可能会向前或向后跳,从而给您的基准测试提供不准确的结果。

更好的解决方案是使用操作系统的单调时钟,它总是向前移动。 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

您可以阅读更多详细信息here。您还可以看到流行的 Ruby 项目 Sidekiq 已切换到 monotonic clock。

【讨论】:

提供秒以外的其他单位(ms、µs、ns、...),请参阅core doc【参考方案5】:

再想一想,使用 Ruby 代码块参数定义 measure() 函数可以帮助简化时间测量代码:

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。请解决这个问题。【参考方案6】:

本着wquist's answer的精神,但更简单一点,你也可以像下面这样:

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

【讨论】:

这个答案是一种(稍微)不同的回答问题的方式。仅仅因为您可以从@wquist 的回答中弄清楚并不意味着它无效。

以上是关于Ruby 方法的测量和基准时间的主要内容,如果未能解决你的问题,请参考以下文章

Ruby基准测试一条多次运行的线[关闭]

ruby 简单的基准2红宝石方法

JMH java Mocrobenchmark Harness 方法级精准测量工具 概述

三坐标测量机建立坐标系的方法

如何测量网络性能(如何对网络协议进行基准测试)

是否有正确的功能基准测试方法? [复制]