Created
October 16, 2010 11:56
-
-
Save pjb3/629716 to your computer and use it in GitHub Desktop.
Apparently attr_reader is faster than a method in all ruby implementations. Why?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'benchmark' | |
puts | |
puts ENV["RUBY_VERSION"] | |
class A | |
def initialize(foo) | |
@foo = foo | |
end | |
def foo | |
@foo | |
end | |
end | |
class B | |
attr_reader :foo | |
def initialize(foo) | |
@foo = foo | |
end | |
end | |
a = A.new "foo" | |
b = B.new "foo" | |
Benchmark.bmbm do |x| | |
x.report("method") { 1_000_000.times { a.foo } } | |
x.report("attr_reader") { 1_000_000.times { b.foo } } | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ rvm ruby method_vs_attr_reader.rb | |
jruby-1.5.2 | |
Rehearsal ----------------------------------------------- | |
method 0.241000 0.000000 0.241000 ( 0.193000) | |
attr_reader 0.082000 0.000000 0.082000 ( 0.082000) | |
-------------------------------------- total: 0.323000sec | |
user system total real | |
method 0.060000 0.000000 0.060000 ( 0.060000) | |
attr_reader 0.050000 0.000000 0.050000 ( 0.050000) | |
rbx-1.1.0-20100923 | |
Rehearsal ----------------------------------------------- | |
method 0.242164 0.001986 0.244150 ( 0.139181) | |
attr_reader 0.089972 0.000132 0.090104 ( 0.077365) | |
-------------------------------------- total: 0.334254sec | |
user system total real | |
method 0.050219 0.000019 0.050238 ( 0.050255) | |
attr_reader 0.036286 0.000028 0.036314 ( 0.036333) | |
ree-1.8.6-20090610 | |
Rehearsal ----------------------------------------------- | |
method 0.190000 0.000000 0.190000 ( 0.189835) | |
attr_reader 0.130000 0.000000 0.130000 ( 0.131267) | |
-------------------------------------- total: 0.320000sec | |
user system total real | |
method 0.180000 0.000000 0.180000 ( 0.182960) | |
attr_reader 0.140000 0.000000 0.140000 ( 0.136712) | |
ree-1.8.7-2010.02 | |
Rehearsal ----------------------------------------------- | |
method 0.220000 0.000000 0.220000 ( 0.219702) | |
attr_reader 0.120000 0.000000 0.120000 ( 0.126708) | |
-------------------------------------- total: 0.340000sec | |
user system total real | |
method 0.210000 0.000000 0.210000 ( 0.208938) | |
attr_reader 0.140000 0.000000 0.140000 ( 0.133091) | |
ruby-1.9.2-p0 | |
Rehearsal ----------------------------------------------- | |
method 0.130000 0.000000 0.130000 ( 0.127519) | |
attr_reader 0.100000 0.000000 0.100000 ( 0.098922) | |
-------------------------------------- total: 0.230000sec | |
user system total real | |
method 0.130000 0.000000 0.130000 ( 0.131623) | |
attr_reader 0.100000 0.000000 0.100000 ( 0.102913) |
Very cool, thanks for the explanation!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
There a special optimizations done for
attr_*
. The way MRI works is it stores the parsed code as a tree, then when executing, it walks the tree. In the case of normal methods likedef foo; @foo end
, MRI must do lots of work like set up stack frames, check for stack overflow, set up the environment (like access to class variables, etc). Withattr_*
, the interpreter knows in advance that it's simply an ivar lookup (which is basically a hash lookup).Take a look here to see how MRI evaluates
attr_*
methods, then here for normal methods. If you follow the function calls for normal methods, you'll step in tovm_setup_method
and you can see how much work it is to call a normal method. Compare that to theattr_*
method calls and you'll see whyattr_*
is so much faster.I'm not familiar with the internals of the other implementations, but I suspect they have similar optimizations. Hope that helps!