Ruby有一个内置的loop
命令,可以永久地执行它后面的块(或直到break
停止)。但是,将它与功能相似的while true
进行比较时,速度要慢得多:
require "benchmark/ips"
NUMBER = 100_000_000
def fast
index = 0
while true
break if index > NUMBER
index += 1
end
end
def slow
index = 0
loop do
break if index > NUMBER
index += 1
end
end
Benchmark.ips do |x|
x.report("While Loop") { fast }
x.report("Kernel loop") { slow }
x.compare!
end
在Ruby 2.4.1(p111(2017-03-22修订版58053)[x64-mingw32])下,差异非常明显:
Warming up --------------------------------------
While Loop 1.000 i/100ms
Kernel loop 1.000 i/100ms
Calculating -------------------------------------
While Loop 0.630 (± 0.0%) i/s - 4.000 in 6.350897s
Kernel loop 0.190 (± 0.0%) i/s - 1.000 in 5.274249s
Comparison:
While Loop: 0.6 i/s
Kernel loop: 0.2 i/s - 3.32x slower
为什么会出现这样的性能差异?为什么单一目的loop
命令更糟糕在其工作中比通用目的while
更糟糕?
(从here复制的基准,在CC-BY-SA下获得许可)
答案 0 :(得分:6)
loop
是一个采用block
的内核方法。提醒一下,block
介绍新的局部变量范围。
例如:
loop do
a = 2
break
end
puts a
将返回错误,例如:“ NameError:未定义的局部变量或方法`a'for main:Object ” 另一方面:
while true
a = 2
break
end
p a #=> return a = 2
所以我不会感到惊讶的是loop
创建某种局部变量,例如一个用于break语句的局部变量,它将在其范围内。在每次迭代时创建/删除这些变量都会减慢过程。
答案 1 :(得分:-4)
通常,为了从基准测试中获得更准确的结果,您可以增加测试次数,并在基准数量上平均结果。
while
循环有条件检查每个循环的顶部,相反loop do...end
没有条件不检查。因此,即使条件为真,计算的逻辑也就越少,它仍然至少要进行一次检查。