使用此代码:
include Benchmark n = 10**8 r = [] Benchmark.benchmark(" "*7 + CAPTION,7,FORMAT,">avg:",">total:") do |b| a = 1 r << b.report("Benchmark -1:") { (n).times do -1 * a end } r << b.report("Benchmark - :") { (n).times do -a end } [(r.sum{|e| e }) / 2,r.sum{|e| e }] end
我在ruby 2.1.5p273(2014-11-13修订版48405)[x86_64-linux]上得到了这个结果:
user system total real Benchmark -1: 4.930000 0.000000 4.930000 ( 4.938359) Benchmark - : 5.650000 0.000000 5.650000 ( 5.667566) >avg: 5.290000 0.000000 5.290000 ( 5.302962) >total: 10.580000 0.000000 10.580000 ( 10.605924)
这看起来很直观,因为如果我猜我会打赌“-x”而不是“-1 * x”更快.
为什么不同?或者我的测量中存在一些重大缺陷?
解决方法
如果查看生成的字节码,它可能会有所帮助.如果你将它简化为简单的东西
puts RubyVM::InstructionSequence.compile(<<-CODE a = 1 -1 * a CODE ).to_a.join("\n") puts RubyVM::InstructionSequence.compile(<<-CODE a = 1 -a CODE ).to_a.join("\n")
您还可以使用#〜$ruby –dump insns -e’code’来打印指令序列(如@Stefan所述),这将实际输出更清晰的输出.
#~$ruby --dump insns -e 'a = 1; -a' == disasm: <RubyVM::InstructionSequence:<main>@-e>====================== local table (size: 2,argc: 0 [opts: 0,rest: -1,post: 0,block: -1] s1) [ 2] a 0000 trace 1 ( 1) 0002 putobject 1 0004 setdynamic a,0 0007 trace 1 0009 getdynamic a,0 0012 send :-@,nil,<ic:0> 0018 leave #~$ruby --dump insns -e 'a = 1; -1 * a' == disasm: <RubyVM::InstructionSequence:<main>@-e>====================== local table (size: 2,0 0007 trace 1 0009 putobject -1 0011 getdynamic a,0 0014 opt_mult <ic:1> 0016 leave
你会注意到在字节码列表中,在-1 *中,Ruby做了一个opt_mult,它基本上只是一个算术运算,并在内部进行了优化.另一方面,-a位是opt_send_without_block,它是实际的方法调用.我的猜测是这就是为什么第二个版本(有点)慢了.