概要
処理をバスッと切ってユーザーにエラーを表示させるようなシチュエーション、例えばAjaxのレスポンスなどで、ロールバックのことなんかも考えるとraiseを使うと便利だと思ったのですが、バックトレースが必要ないので、生成しないようにできたら多少でも軽くなるかなと思って調べてみた。
コード
raise StandardError, 'そんなことしたらあかん!', []
raiseの3番目の引数に空の配列を渡すと生成されないっぽい。
Catch/Throw
Catch/Throwのことを思い出し試してみた。
ただ、catchの返り値が正常終了時はブロックの返り値、throwするとthrowした値というのが使い勝手が悪かったのと、railsのrescue_fromで処理できないのでアクションごとにごにょごにょ書かいないとダメなのがいまいちだった。
message = catch :error do
throw :error,'そんなことしたらあかん!'
# ここで何か処理をするとその返り値がmessageに入り`if message.nil?`がfalseに
end
ベンチマーク
本当にバックトレースが生成されてないのか(かどうかはわからないが早くなってるかどうか)チェックしてみた。
user system total real
Backtrace 0.098349 0.001307 0.099656 ( 0.099900)
EmptyBacktrace 0.060658 0.000319 0.060977 ( 0.061093)
Catch/Throw 0.032181 0.000067 0.032248 ( 0.032283)
Backtrace 0.107247 0.001669 0.108916 ( 0.109663)
EmptyBacktrace 0.062382 0.000346 0.062728 ( 0.063138)
Catch/Throw 0.035800 0.000467 0.036267 ( 0.036668)
user system total real
Backtrace 0.102345 0.001523 0.103868 ( 0.104327)
EmptyBacktrace 0.059909 0.000370 0.060279 ( 0.060521)
Catch/Throw 0.032488 0.000130 0.032618 ( 0.032768)
3回取ってみた感じはこんな感じ。やっぱりCatch/Throwの方が早いですね。ただ、空バックトレースも一定の効果はありそうです。
参考までにベンチマークのコードはこんな感じ。
require 'benchmark'
count = 100000
Benchmark.bm 15 do |r|
r.report "Backtrace" do
count.times do
begin
raise StandardError, 'FOOOOOOOOO'
rescue
end
end
end
r.report "EmptyBacktrace" do
count.times do
begin
raise StandardError, 'FOOOOOOOOO', []
rescue
end
end
end
r.report "Catch/Throw" do
count.times do
catch :foo do
throw :foo, 'FOOOOOOOOO'
end
end
end
end
ベンチマークって平等にやるの意外に難しいですよね。問題に気づいたら教えてください。