Ruby exceptions
At work a discussion arised on how fast a ruby exception is. And if it is usable in Rails projects. The discussion started after the conclusion that performance dramatically degraded in a project using the Rails framework.
The question arose how fast ruby handles exceptions. After doing a quick google I could not find an isolated benchmark so I whipped up one myself.
Below the result of the benchmark.
ruby 1.8.7 (2012-02-08 patchlevel 358) [i686-darwin11.2.0]
Rehearsal ----------------------------------------------------
exception 0.770000 0.030000 0.800000 ( 0.809420)
exception with e 0.780000 0.040000 0.820000 ( 0.814608)
multi exception 0.850000 0.040000 0.890000 ( 0.885843)
symbol 0.040000 0.000000 0.040000 ( 0.035782)
------------------------------------------- total: 2.550000sec
user system total real
exception 0.770000 0.030000 0.800000 ( 0.808482)
exception with e 0.780000 0.040000 0.820000 ( 0.817195)
multi exception 0.850000 0.040000 0.890000 ( 0.889478)
symbol 0.040000 0.000000 0.040000 ( 0.036175)
ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-darwin11.2.0]
Rehearsal ----------------------------------------------------
exception 0.890000 0.040000 0.930000 ( 0.929162)
exception with e 0.890000 0.030000 0.920000 ( 0.934193)
multi exception 0.970000 0.040000 1.010000 ( 0.999004)
symbol 0.020000 0.000000 0.020000 ( 0.017207)
------------------------------------------- total: 2.880000sec
user system total real
exception 0.830000 0.040000 0.870000 ( 0.867102)
exception with e 0.830000 0.030000 0.860000 ( 0.873007)
multi exception 0.910000 0.040000 0.950000 ( 0.938906)
symbol 0.020000 0.000000 0.020000 ( 0.017294)
jruby 1.6.7.2 (ruby-1.8.7-p357) (2012-05-01 26e08ba) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_29) [darwin-x86_64-java]
Rehearsal ----------------------------------------------------
exception 8.044000 0.000000 8.044000 ( 8.006000)
exception with e 7.704000 0.000000 7.704000 ( 7.704000)
multi exception 7.791000 0.000000 7.791000 ( 7.791000)
symbol 0.038000 0.000000 0.038000 ( 0.038000)
------------------------------------------ total: 23.577000sec
user system total real
exception 7.603000 0.000000 7.603000 ( 7.603000)
exception with e 7.605000 0.000000 7.605000 ( 7.605000)
multi exception 7.529000 0.000000 7.529000 ( 7.529000)
symbol 0.009000 0.000000 0.009000 ( 0.009000)
The benchmark code
require 'benchmark'
class E1 < StandardError; end
class E2 < StandardError; end
class E3 < StandardError; end
def outer_conditional
if inner_returns_symbol == :argument_error
:agument_error
end
end
def outer_multi_exception
inner_multi_exception
rescue E1
:E1
rescue E2
:E2
rescue E3
:E3
end
def inner_multi_exception
raise [E1, E2, E3][rand(3)]
end
def outer_exception
inner_raises_exception
rescue ArgumentError
:argument_error
end
def outer_exception_with_e
inner_raises_exception
rescue ArgumentError => e
:argument_error
end
def inner_raises_exception
raise ArgumentError
end
def inner_returns_symbol
:argument_error
end
COUNT = 100_000
Benchmark.bmbm { |x|
x.report("exception") do
COUNT.times { outer_exception }
end
x.report("exception with e") do
COUNT.times { outer_exception_with_e }
end
x.report("multi exception") do
COUNT.times { outer_multi_exception }
end
x.report("symbol") do
COUNT.times { outer_conditional }
end
}