Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why might a proc run faster than a block?

Tags:

ruby

internals

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?

like image 517
Nathan Long Avatar asked Jul 14 '12 02:07

Nathan Long


2 Answers

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.

like image 55
Daniel Vartanov Avatar answered Oct 21 '22 15:10

Daniel Vartanov


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.

like image 40
Frederick Cheung Avatar answered Oct 21 '22 13:10

Frederick Cheung