ruby で多重ループから抜けるには、シンプルにフラグを用意して if で break する方法と、throw, raise を利用する方法がある(もっとあったら教えてください)。その3つの方法の速度比較をしてみた。

ruby 2.0.0p247 (2013-06-27 revision 41674)

require 'benchmark'
n = 1000000

foo = nil
Benchmark.bm(7, ">throw", ">raise:", ">break:") do |x|
  a = x.report("throw") { n.times {
    catch(:foo) do
      while true
        while true
          throw :foo if foo.nil?
        end
      e
    end
  }}
  b = x.report("raise") { n.times {
    begin
      while true
        while true
          raise :foo if foo.nil?
        end
      end
    rescue
    end
  }}
  c = x.report("break") { n.times {
    is_break = false
    while true
      while true
        is_break = true and break if foo.nil?
      end
      break if is_break
    end
  }}
end

結果は以下のようになった。

              user     system      total        real
throw     0.660000   0.000000   0.660000 (  0.664681)
raise     4.250000   0.070000   4.320000 (  4.468123)
break     0.380000   0.000000   0.380000 (  0.393236)

raise 遅っ!!例外オブジェクトを作るからでしょうね。throw よりも break 2回するほうが早かった。 けど、フラグ用意する手間を考えると throw が一番妥当じゃないですかね。

おわり