如何衡量eval“def ...”和define_method的性能

时间:2013-02-25 16:27:24

标签: ruby metaprogramming eval

在RubyMonk中进行练习(在支付墙后面的链接,因此未提供),为了衡量使用evaldefine_method相比定义方法的性能,提供了以下代码:

require 'benchmark'

class Monk
  eval "def zen; end"

  define_method(:zen_block) {}
end

monk = Monk.new

Benchmark.bmbm do |x|
  x.report("eval zen: ") { 1_000_000.times { monk.zen } }
  x.report("define_method zen: ") { 1_000_000.times { monk.zen_block } }
end

作为Ruby的新手,我的问题是:解释器何时实际“编译”了方法zenzen_block(不确定它是否是正确的单词)?似乎不太可能在每次调用时重新定义zenzen_block。从我到目前为止所理解的情况来看,在我看来,衡量绩效,正确的方法是:

require 'benchmark'

class Monk
  def with_eval
    eval "def zen; end"
  end

  def with_define_method
    self.class.send(:define_method,:zen_block) {}
  end
end

Benchmark.bmbm do |x|
  x.report("eval zen: ") { 1_000_000.times { monk.with_eval } }
  x.report("define_method zen: ") { 1_000_000.times { monk.with_define_method } }
end

第一个块在我的机器中产生这些结果(我已经将迭代次数提高到100万,以使时间更加稳健):

Rehearsal -------------------------------------------------------
eval zen:             0.070000   0.000000   0.070000 (  0.074196)
define_method zen:    0.120000   0.000000   0.120000 (  0.118621)
---------------------------------------------- total: 0.190000sec

第二个区块的结果(我的建议):

Rehearsal -------------------------------------------------------
eval zen:             7.740000   0.000000   7.740000 (  7.743741)
define_method zen:    1.620000   0.000000   1.620000 (  1.617666)
---------------------------------------------- total: 9.360000sec

2 个答案:

答案 0 :(得分:3)

您从RubyMonk显示的基准测试不是衡量定义方法的速度evaldefine_method。它测量调用结果方法的速度。这就是它为什么会这样做的原因。

在您了解有关Ruby解释器实现的更多信息之前,由于您可能不明白的原因,通过evaldefine_method定义的方法的速度通常不一样。< / p>

答案 1 :(得分:3)

感谢您向我们指出这一点。

你是对的,主题应该措辞如下:'比较由define_method'创建的eval v / s方法创建的动态方法的性能。

我们将在今天晚些时候在我们的内容中修复此错误。

虽然定义方法的性能增量是一个重要的考虑因素,但我们从来没有看到它具有太大的实际意义(至少在ruby中),特别是因为AST会被缓存。

特加斯

RubyMonk团队

相关问题