是什么使Ruby中的'while'循环比其他循环更快?
我正在使用以下代码:是什么使Ruby中的'while'循环比其他循环更快?,ruby,Ruby,我正在使用以下代码: require 'benchmark' LOOPS = 100_000_000 def while_loop i = 0 while i < LOOPS do i += 1 end end def times_loop i = 0 LOOPS.times { i += 1 } end Benchmark.benchmark do |b| b.report('while') { w
require 'benchmark'
LOOPS = 100_000_000
def while_loop
i = 0
while i < LOOPS do i += 1 end
end
def times_loop
i = 0
LOOPS.times { i += 1 }
end
Benchmark.benchmark do |b|
b.report('while') { while_loop }
b.report('times') { times_loop }
end
为什么
而循环比其他循环快?其中一个原因是次
-它是一个块。并引入了新的局部变量作用域。它创建了某种局部变量,看:
RubyVM::InstructionSequence.disasm(方法(:times\u循环))
返回
== disasm: #<ISeq:times_loop@1.rb:23 (23,0)-(26,3)>=====================
== catch table
| catch type: break st: 0003 ed: 0014 sp: 0000 cont: 0014
== disasm: #<ISeq:block in times_loop@1.rb:25 (25,14)-(25,24)>==========
== catch table
| catch type: redo st: 0001 ed: 0010 sp: 0000 cont: 0001
| catch type: next st: 0001 ed: 0010 sp: 0000 cont: 0010
|------------------------------------------------------------------------
0000 nop ( 25)[Bc]
0001 getlocal_OP__WC__1 i[Li]
0003 putobject_OP_INT2FIX_O_1_C_
0004 opt_plus <callinfo!mid:+, argc:1, ARGS_SIMPLE>, <callcache>
0007 dup
0008 setlocal_OP__WC__1 i
0010 leave [Br]
|------------------------------------------------------------------------
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] i
0000 putobject_OP_INT2FIX_O_0_C_ ( 24)[LiCa]
0001 setlocal_OP__WC__0 i
0003 getinlinecache 10, <is:0> ( 25)[Li]
0006 getconstant :LOOPS
0008 setinlinecache <is:0>
0010 send <callinfo!mid:times, argc:0>, <callcache>, block in times_loop
0014 leave ( 26)[Re]
== disasm: #<ISeq:while_loop@1.rb:15 (15,0)-(20,3)>=====================
== catch table
| catch type: break st: 0009 ed: 0032 sp: 0000 cont: 0032
| catch type: next st: 0009 ed: 0032 sp: 0000 cont: 0006
| catch type: redo st: 0009 ed: 0032 sp: 0000 cont: 0009
|------------------------------------------------------------------------
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] i
0000 putobject_OP_INT2FIX_O_0_C_ ( 16)[LiCa]
0001 setlocal_OP__WC__0 i
0003 jump 17 ( 17)[Li]
0005 putnil
0006 pop
0007 jump 17
0009 getlocal_OP__WC__0 i ( 18)[Li]
0011 putobject_OP_INT2FIX_O_1_C_
0012 opt_plus <callinfo!mid:+, argc:1, ARGS_SIMPLE>, <callcache>
0015 setlocal_OP__WC__0 i
0017 getlocal_OP__WC__0 i ( 17)
0019 getinlinecache 26, <is:0>
0022 getconstant :LOOPS
0024 setinlinecache <is:0>
0026 opt_lt <callinfo!mid:<, argc:1, ARGS_SIMPLE>, <callcache>
0029 branchif 9
0031 putnil
0032 leave ( 20)[Re]
我认为原因并不是唯一的
但是设置/获取新的局部变量会减慢操作。循环。times
会创建一个枚举器(=>#
),因此必须执行代码来生成枚举器的每个元素并将其传递给块,即使块计算中没有使用该值。我认为这就是性能差异的原因,但我没有证据。@CarySwoveland我认为值得注意的是,(1..循环)。每个
的性能与循环的性能相似。时间
和f=->(){I+=1};(1..循环)。每个(&f)
都稍微慢一点。我会胡乱猜测,这涉及到块调用开销,但我必须深入研究源代码,看看是如何实现的,而是如何实现的。我认为在没有任何参数的情况下调用块会使调用速度变慢。。。例如,如果您有yield,那么您的代码必须执行yield,即使您没有给出块参数……这在很大程度上取决于实现。例如,我非常确信块菌菌能够完全消除简单的积木。而且,在这种情况下,任何半途而废的Ruby实现都能够消除局部变量。
== disasm: #<ISeq:while_loop@1.rb:15 (15,0)-(20,3)>=====================
== catch table
| catch type: break st: 0009 ed: 0032 sp: 0000 cont: 0032
| catch type: next st: 0009 ed: 0032 sp: 0000 cont: 0006
| catch type: redo st: 0009 ed: 0032 sp: 0000 cont: 0009
|------------------------------------------------------------------------
local table (size: 1, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 1] i
0000 putobject_OP_INT2FIX_O_0_C_ ( 16)[LiCa]
0001 setlocal_OP__WC__0 i
0003 jump 17 ( 17)[Li]
0005 putnil
0006 pop
0007 jump 17
0009 getlocal_OP__WC__0 i ( 18)[Li]
0011 putobject_OP_INT2FIX_O_1_C_
0012 opt_plus <callinfo!mid:+, argc:1, ARGS_SIMPLE>, <callcache>
0015 setlocal_OP__WC__0 i
0017 getlocal_OP__WC__0 i ( 17)
0019 getinlinecache 26, <is:0>
0022 getconstant :LOOPS
0024 setinlinecache <is:0>
0026 opt_lt <callinfo!mid:<, argc:1, ARGS_SIMPLE>, <callcache>
0029 branchif 9
0031 putnil
0032 leave ( 20)[Re]