Ruby 中的基准测试方法



我正在尝试对一组这样的计算进行基准测试 -

def benchmark(func, index, array)
    start = Time.now
    func(index, array)
    start - Time.now #returns time taken to perform func
end
def func1(index, array)
    #perform computations based on index and array
end 
def func2(index, array)
    #more computations....
end
benchmark(func1, index1, array1)
benchmark(func1, index2, array2)

现在我想知道如何实现这一目标。我尝试了这个例子,但被吐了出来

`func1': wrong number of arguments (0 for 2) (ArgumentError)

如果我尝试 -

benchmark(func1(index1, array1), index1, array1)

它吐出来...

undefined method `func' for main:Object (NoMethodError)

我看到一个类似的问题被问到,但它是针对 python 的。将带有参数的函数传递给 Python 中的另一个函数?有人可以协助吗?谢谢。

在 Ruby 中,可以在方法名称后不包含空括号的情况下调用方法,如下所示:

def func1
  puts "Hello!"
end
func1 # Calls func1 and prints "Hello!"

正因为如此,当你编写benchmark(func1, index1, array1)时,你实际上是在没有参数的情况下调用func1并将结果传递给benchmark,而不是像预期的那样将func1传递给基准函数。为了将func1作为对象传递,您可以使用 method 方法获取函数的包装器对象,如下所示:

def func1
  puts "Hello!"
end
m = method(:func1) # Returns a Method object for func1
m.call(param1, param2)

但大多数时候,这不是你真正想做的事情。 Ruby 支持一种称为块的构造,它更适合此目的。您可能已经熟悉 Ruby 用于循环数组的迭代器each块。以下是为您的用例使用块的外观:

def benchmark
  start = Time.now
  yield
  Time.now - start # Returns time taken to perform func
end
# Or alternately:
# def benchmark(&block)
#   start = Time.now
#   block.call
#   Time.now - start # Returns time taken to perform func
# end
def func1(index, array)
    # Perform computations based on index and array
end 
def func2(index, array)
    # More computations....
end
benchmark { func1(index1, array1) }
benchmark { func1(index1, array2) }

事实上,Ruby有一个标准的基准测试库,称为Benchmark,它使用块,并且可能已经完全按照你想要做了。

用法:

require 'benchmark'
n = 5000000
Benchmark.bm do |x|
  x.report { for i in 1..n; a = "1"; end }
  x.report { n.times do   ; a = "1"; end }
  x.report { 1.upto(n) do ; a = "1"; end }
end

结果:

    user     system      total        real
1.010000   0.000000   1.010000 (  1.014479)
1.000000   0.000000   1.000000 (  0.998261)
0.980000   0.000000   0.980000 (  0.981335)

您似乎正在尝试将 Ruby 方法用作函数。这并不常见,但完全有可能。

def benchmark(func, index, array)
    start = Time.now
    func.call(index, array) # <= (C)
    start - Time.now
end
def func1(index, array)
    #perform computations based on index and array
end 
def func2(index, array)
    #more computations....
end
benchmark(method(:func1), index1, array1) # <= (A)
benchmark(method(:func1), index2, array2) # <= (B)

对代码的更改如下所示:

A, B(从以前定义的方法创建一个Method对象。Method对象类似于Proc对象,因为它具有允许您稍后调用它的call方法。在你的代码中,当你只使用func1而不是method(:func1)时,发生的事情是你立即调用该方法并将其结果传递给benchmark,而不是将函数本身传递到benchmark以供以后调用。

C( 使用call方法。Ruby 不允许你像其他一些语言那样使用括号任意调用变量作为函数,但如果它是具有call方法的对象类型,如MethodProc,您可以使用call在准备好时调用函数,而不是在尝试将其传递给另一个方法之前立即调用, 就像您的原始代码一样。

这是我的做法。 我首先创建一个包含所有要测试的方法的模块:

module Methods
  def bob(array)
    ...
  end
  def gretta(array
    ...
  end
  def wilma(array)
    ...
  end
end

然后我包含模块并将方法放入数组中:

include Methods
@methods = Methods.public_instance_methods(false)
  #=> [:bob, :gretta, :wilma]

这使我能够为@methodsmeth的每个方法执行send(meth, *args)

下面是此方法的示例。您将看到我还有代码来检查所有方法是否返回相同的结果并格式化输出。

主例程可能如下所示:

test_sizes.each do |n|
  puts "nn = #{n}"
  arr = test_array(n)
  Benchmark.bm(@indent) do |bm|
    @methods.each do |m|
      bm.report m.to_s do
        send(m, arr)
     end
    end
  end
end

我使用一个模块,以便可以添加、删除或重命名要基准测试的方法,而无需接触模块外部的任何代码。

class SimpleBenchmarker
    def self.go(how_many=1, &block)
        $sorted_time = Array.new
        puts "n--------------Benchmarking started----------------"
        start_time = Time.now
        puts "Start Time:t#{start_time}nn"
        how_many.times do |a|
            print "."
            block.call
        end
        print "nn"
        end_time = Time.now
        puts "End Time:t#{end_time}n"
        puts "-------------Benchmarking finished----------------nn"
        result_time = end_time - start_time
        puts "Total time:tt#{result_time.round(3)} secondsnn"
        puts "The run times for the iterations from shortest to longest was: #{$sorted_time.sort.join("s, ")}snn"
    end
end
    print "How many times? "
    t = gets.to_i
SimpleBenchmarker.go t do
    time = rand(0.1..1.0).round(3)
    $sorted_time.push(time)
    sleep time
end

请检查我的新 gem,它可以分析您的 ruby 方法(实例或类( - https://github.com/igorkasyanchuk/benchmark_methods。

没有更多的代码像这样:

t = Time.now
user.calculate_report
puts Time.now - t

现在您可以执行以下操作:

benchmark :calculate_report # in class

只需调用您的方法

user.calculate_report

相关内容

  • 没有找到相关文章

最新更新