4

这很丑陋:

t = Time.now
result = do_something
elapsed = Time.now - t

我试过这个:

elapsed = time do
  result = do_something
end

def time
  t = Time.now
  yield
  Time.now - t
end

这个更好。但问题是result块结束后超出范围。

那么,有没有更好的计时方法呢?还是使用的好方法result

4

3 回答 3

4

一个真正惯用的方法是使用标准库。:)

require 'benchmark'

result = nil
elapsed = Benchmark.realtime do 
  result = do_something
end
于 2016-09-22T17:30:52.320 回答
2

我喜欢你构建time方法的方式。我没有改进的建议,但我会就一个相关的问题说几句话。假设您希望测量执行方法所花费的时间。有时你可以写一些简单的东西,例如:

require 'time'

t = Time.now
rv = my_method(*args)
et = t.Time.now - t

其他时候不方便。例如,假设您正在构造一个数组,其元素是枚举数的返回值my_methodmy_method返回一个枚举数,以便它可以链接到其他方法。

例如,假设您想对数组的值求和,直到遇到零。一种方法是构造一个枚举器,该枚举stop_at_zero器从其接收器生成值,直到遇到零,然后停止(即引发StopIteration异常)。然后我们可以写:

arr.stop_at_zero.reduce(:+)

如果我们想知道执行花费了多少时间,stop_at_zero我们可以如下构造它。

class Array
  def stop_at_zero
    extime = Time.now
    Enumerator.new do |y|
      begin
        each do |n|
          sleep(0.5)
          return y if n.zero?
          y << n
        end
      ensure
        $timings << [__method__, Time.now - extime]
      end
    end
  end
end

我使用了begin, ensure,end块来确保$timings << [__method__, Time.now - extime]在方法过早返回时执行。sleep(0.5)当然只是为了说明的目的。

让我们试试看。

$timings = []
arr = [1,7,0,3,4]
arr.stop_at_zero.reduce(:+)
  #=> 8 
$timings
  #=> [[:stop_at_zero, 1.505672]] 

$timings将包含包含计时代码的所有方法的执行时间历史记录。

于 2016-09-23T00:32:56.510 回答
2

您在这里有正确的想法,但要避免范围问题,请执行以下操作:

result = nil
elapsed = time do
  result = do_something
end
于 2016-09-22T17:26:08.553 回答