Reputation: 1146
Ruby has a built-in loop
command that executes the block following it forever (or until stopped by break
). However, when comparing it against the functionally similar while true
, it is significantly slower:
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
Under Ruby 2.4.1 (p111 (2017-03-22 revision 58053) [x64-mingw32]), the difference is striking:
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
Why is there such a performance difference? And why is the single-purpose loop
command worse at its job than the general-purpose while
?
(Benchmark copied from here, licensed under CC-BY-SA)
Upvotes: 9
Views: 2075
Reputation: 2344
loop
is a kernel method which takes a block
. As a reminder, a block
introduces new local variable scope.
For example:
loop do
a = 2
break
end
puts a
Will return an error such as: "NameError: undefined local variable or method `a' for main:Object" On the other hand:
while true
a = 2
break
end
p a #=> return a = 2
So I wouldn't be surprised that loop
creates some sort of local variable(s) such as one for the break statement that is (are) going to be in its scope. Creating/deleting those variables at every iteration slow down the process.
Upvotes: 10
Reputation: 37
Generally to get more accurate results from a benchmark you can increase the number of times you do your test and average the results across the number of benchmarks.
The while
loop has a conditional to check at the top of every loop, and in contrast loop do...end
has no conditional does not. So it is computing less logic even if that conditional is true, it is still doing at least one check more.
Upvotes: -5