Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the &method(:method_name) idiom bad for performance in Ruby?

I've recently come across the &method(:method_name) syntax. (This uses the Object#method method - RDoc link) For example,

[5, 7, 8, 1].each(&method(:puts))

is the equivalent of

[5, 7, 8, 1].each{|number| puts number}

Are there performance penalties for the latter compared to the former in the various implementations of Ruby? If so, are the implementors working on improving its performance?

like image 787
Andrew Grimm Avatar asked Aug 07 '11 23:08

Andrew Grimm


1 Answers

Yes, it appears to be bad for performance.

def time
  start = Time.now
  yield
  "%.6f" % (Time.now - start)
end

def do_nothing(arg)
end


RUBY_VERSION # => "1.9.2"

# small
ary = *1..10
time { ary.each(&method(:do_nothing)) }     # => "0.000019"
time { ary.each { |arg| do_nothing arg } }  # => "0.000003"


# large
ary = *1..10_000
time { ary.each(&method(:do_nothing)) }     # => "0.002787"
time { ary.each { |arg| do_nothing arg } }  # => "0.001810"


# huge
ary = *1..10_000_000
time { ary.each(&method(:do_nothing)) }     # => "37.901283"
time { ary.each { |arg| do_nothing arg } }  # => "1.754063"

It looks like this is addressed in JRuby:

$ rvm use jruby
Using /Users/joshuajcheek/.rvm/gems/jruby-1.6.3

$ xmpfilter f.rb 
def time
  start = Time.now
  yield
  "%.6f" % (Time.now - start)
end

def do_nothing(arg)
end


RUBY_VERSION # => "1.8.7"

# small
ary = *1..10
time { ary.each(&method(:do_nothing)) }     # => "0.009000"
time { ary.each { |arg| do_nothing arg } }  # => "0.001000"


# large
ary = *1..10_000
time { ary.each(&method(:do_nothing)) }     # => "0.043000"
time { ary.each { |arg| do_nothing arg } }  # => "0.055000"


# huge
ary = *1..10_000_000
time { ary.each(&method(:do_nothing)) }     # => "0.427000"
time { ary.each { |arg| do_nothing arg } }  # => "0.634000"
like image 106
Joshua Cheek Avatar answered Nov 16 '22 02:11

Joshua Cheek