This answer on another question says that
array.map(&:to_s)
is faster than
array.map { |n| n.to_s }
In the first example, &
turns :to_s
into a Proc. The second example uses a block.
Why might a Proc be faster than a block in that benchmark? Is there some optimization that this technique allows the interpreter to do?
It is not really about "proc vs block".
Here is a simple experiment (feel free to copy and run):
require 'benchmark'
many = 500
array = (1..10000).to_a
proc = proc { |a| a.to_s }
Benchmark.bm do |x|
x.report('Symbol#to_proc') { many.times { array.map(&:to_s) } }
x.report('proc') { many.times { array.map(&proc) } }
x.report('block') { many.times { array.map { |a| a.to_s } } }
end
Ruby 1.9.3p194 results:
user system total real
Symbol#to_proc 1.170000 0.000000 1.170000 ( 1.169055)
proc 1.450000 0.000000 1.450000 ( 1.454216)
block 1.450000 0.000000 1.450000 ( 1.448094)
As you see, block
and proc
both take virtually the same amount of CPU time. The magic is inside Symbol#to_proc
itself.
As others have been said this is specifically about Symbol#to_proc
rather than procs in general and it is almost certainly ruby implementation dependant. Before Symbol#to_proc
was in ruby itself, the pure ruby implementations of it were definitely slower the the equivalent block.
For a real answer you'd want to profile ruby while you're executing such a benchmark.
My reading of the ruby source code is that when you call Symbol#to_proc
the proc you get is a bit special: The body of the proc is just a C api call (rb_funcall_passing_block
), whereas in the other cases it's actual ruby code which takes a little longer to execute.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With