Ruby performance: #attr_accessor vs. method definition
February 19, 2018
I’ve been digging a lot into Ruby performance lately and this much digging has taken me into some very interesting corners of Rubyland. My latest surprise has been the difference between defining attribute methods via the attr_accessor
provided language construct (as well as attr_reader
and attr_writer
) vs. defining them yourself (as in def attribute
and def attribute=
). Here’s what I ran into…
I created two simple classes with identical interfaces. The only difference between the two is how we are defining access to set and get the @value
attribute in each:
class TestClassAttrAccessor
attr_accessor :value
def initialize value
@value = value
end
end
class TestClassDefMethod
def initialize value
@value = value
end
def value
@value
end
def value= value
@value = value
end
end
Then, I built a script using good ol’ benchmark-ips:
Benchmark.ips do |bm|
with_attr = TestClassAttrAccessor.new 1
with_method = TestClassDefMethod.new 1
bm.report 'attr_accessor' do
with_attr.value = 1
with_attr.value
end
bm.report 'def method' do
with_method.value = 1
with_method.value
end
bm.compare!
end
And, to my surprise, these were the results:
...
Comparison:
attr_accessor: 7039680.3 i/s
def method: 5720331.2 i/s - 1.23x slower
Yeah… I guess 1.23x
is not that much of a difference, but similar to #has_key?
vs. #[]
this results in approximately 1.3 million more iterations per second, which becomes significant when building tries from large dictionaries.
Regardless, I’ll take it. From now on, I’ll use attr_accessor :<attribute>
instead of def <attribute>
whenever possible.
Also, I guess it may be time for me to get a slogan:
gonzedge: optimizing software 1.3 million iterations per second at a time
Hmm, doesn’t really have a nice ring to it 😕
Notes
- I didn’t dig into it much, but I’m pretty sure it has to do with the fact that
attr_accessor
defines the methods via therb_attr
method in C. Running a similar benchmark in Ruby 2.4.0, and there was a bigger gap:
... Comparison: attr_accessor: 6327686.3 i/s def method: 3932535.7 i/s - 1.61x slower