为什么Ruby的循环命令比true更慢?

时间:2017-07-13 00:54:51

标签: ruby performance while-loop infinite-loop

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下获得许可)

2 个答案:

答案 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没有条件不检查。因此,即使条件为真,计算的逻辑也就越少,它仍然至少要进行一次检查。