在RubyMonk中进行练习(在支付墙后面的链接,因此未提供),为了衡量使用eval
与define_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的新手,我的问题是:解释器何时实际“编译”了方法zen
和zen_block
(不确定它是否是正确的单词)?似乎不太可能在每次调用时重新定义zen
和zen_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
答案 0 :(得分:3)
您从RubyMonk显示的基准测试不是衡量定义方法的速度eval
或define_method
。它测量调用结果方法的速度。这就是它为什么会这样做的原因。
在您了解有关Ruby解释器实现的更多信息之前,由于您可能不明白的原因,通过eval
或define_method
定义的方法的速度通常不一样。< / p>
答案 1 :(得分:3)
感谢您向我们指出这一点。
你是对的,主题应该措辞如下:'比较由define_method'创建的eval v / s方法创建的动态方法的性能。
我们将在今天晚些时候在我们的内容中修复此错误。
虽然定义方法的性能增量是一个重要的考虑因素,但我们从来没有看到它具有太大的实际意义(至少在ruby中),特别是因为AST会被缓存。
特加斯
RubyMonk团队