Try to avoid try
Posted by matijs 28/07/2015 at 10h52
Because of a pull request I was working on, I had cause to benchmark activesupport’s #try
. Here’s the code:
require 'benchmark'
require 'active_support/core_ext/object/try'
class Bar
def foo
end
end
class Foo
end
bar = Bar.new
foo = Foo.new
n = 1000000
Benchmark.bmbm(15) do |x|
x.report(’straight’) { n.times { bar.foo } }
x.report(’try - success’) { n.times { bar.try(:foo) } }
x.report(’try - failure’) { n.times { foo.try(:foo) } }
x.report(’try on nil’) { n.times { nil.try(:foo) } }
end
Here is a sample run:
Rehearsal --------------------------------------------------- straight 0.150000 0.000000 0.150000 ( 0.147271) try - success 0.760000 0.000000 0.760000 ( 0.762529) try - failure 0.410000 0.000000 0.410000 ( 0.413914) try on nil 0.210000 0.000000 0.210000 ( 0.207706) ------------------------------------------ total: 1.530000secuser system total real
straight 0.140000 0.000000 0.140000 ( 0.143235) try - success 0.740000 0.000000 0.740000 ( 0.742058) try - failure 0.380000 0.000000 0.380000 ( 0.379819) try on nil 0.210000 0.000000 0.210000 ( 0.207489)
Obviously, calling the method directly is much faster. I often see #try
used defensively, without any reason warrented by the logic of the application. This makes the code harder to follow, and now this benchmark shows that this kind of cargo-culting can actually harm performance of the application in the long run.
Some more odd things stand out:
- Succesful
#try
is slower than failed try plus a straight call. This is because#try
actually does some checks and then calls#try!
which does one of the checks all over again. - Calling
#try
onnil
is slower than calling a nearly identical empty method onfoo
. I don’t really have an explanation for this, but it may have something to do with the fact thatnil
is a special built-in class that may have different logic for method lookup.
Bottom line: #try
is pretty slow because it needs to do a lot of checking before actually calling the tried method. Try to avoid it if possible.