Rubyでのベンチマークの例外-うん、遅い。
私はいつも、他のフロー制御メカニズムと比較して、ルビーでは例外が遅いだろうと強く思っていました。結局のところ、例外は単純な「ブレーク」や「リターン」よりもはるかに複雑です。でも、以前は自分の勘が間違っていたので、試してみようと思いました。
以下のコードでは、benchmark-ips gemを使用して、例外、ブレーク、およびリターンを介してループを終了する相対的なパフォーマンスを比較しています。私はmri1.9でこのようなベンチマークを行っている人々のウェブ上の例を見てきました。しかし、私はmri2.2で試してみたかったのです。
require 'benchmark/ips'
def exit_via_exception
5.times do
raise RuntimeError
end
rescue
end
def exit_via_break
5.times do
break
end
end
def exit_via_return
5.times do
return
end
end
Benchmark.ips do |x|
x.report("exception") { exit_via_exception }
x.report("break") { exit_via_break }
x.report("return") { exit_via_return }
end
結果はかなり驚異的です。例外を使用する関数は、breakandreturnを使用する関数の半分未満の速度です。
$ ruby exception_benchmark.rb
Calculating -------------------------------------
exception 50.872k i/100ms
break 125.322k i/100ms
return 124.173k i/100ms
-------------------------------------------------
exception 714.795k (± 2.7%) i/s - 3.612M
break 3.459M (± 3.1%) i/s - 17.294M
return 3.379M (± 3.0%) i/s - 16.888M
補償方法がわからない問題がいくつかあります。たとえば、exceptionメソッドとbreakメソッドを返す必要があります。したがって、彼らは単に戻るメソッド以上のことをしています。また、例外を救済することでパフォーマンスのオーバーヘッドが増えるかどうかも知りたいと思います。ただし、レスキューしないとベンチマークが中止されます。
それでも、例外は他の例よりもはるかに遅いので、完璧でなくても結果には意味があると思います。
私たちが学んだ教訓は?
フロー制御メカニズムとして例外を使用している場合。今やめて!特に、例外が何度も発生してキャッチされるループがある場合。
これにより、私が個人的に例外を使用する方法が変わりますか?おそらくそうではありません。遅さがルールの例外であるならば、私は少し遅さで生きることができます。 :)
...しかし、JRubyとRBxはどうですか?
Josh Cheek(Twitterの@josh_cheek)は、このベンチマークの独自のバージョンを作成しました。これは、私のものよりも包括的です。そして、彼はそれを複数のルビーの実装に対して実行しました。ここで彼の結果を見ることができます。どうやら休憩はまだ勝者です。 :)
-
Rubyのカスタム例外
Rubyで独自の例外を作成するのは簡単です。次の手順に従ってください: 1。新しいクラスを作成する 例外は、Rubyの他のすべてと同じように、クラスです。新しい種類の例外を作成するには、StandardErrorまたはその子の1つから継承するクラスを作成するだけです。 class MyError < StandardError end raise MyError 慣例により、新しい例外のクラス名は「エラー」で終わります。カスタム例外をモジュール内に配置することもお勧めします。つまり、最終的なエラークラスは次のようになります:ActiveRecord::RecordNotFound
-
Rubyで例外にコンテキストデータを追加する方法
標準のバックトレース/エラーメッセージの組み合わせでは不十分な場合があります。エラーの原因を特定するために、追加のデータが必要になる場合があります。幸い、Rubyで行うのはとても簡単です。 エラーメッセージのカスタマイズ エラーにコンテキスト情報を追加する最も簡単な方法は、それを例外のメッセージに追加することです。以下の例では、例外をキャッチし、新しいメッセージで再発生させています: begin raise foo rescue => e raise e.class, bar end # RuntimeError: bar このアプローチの良い使用例は、テンプレートをレン