【Ruby】ifとcaseで速度比較してみた

zomです。 仕事上でifを連発している過去の自分のソースを見て、caseで書き直したほうが見やすいのでは?と思い、リプレイスしてみました。 やってみたものの「まぁ、多少見やすくなったかな?」程度の結果でした。 肝心なのは「多少の見栄え < 速度」だと思いますので、速度が落ちていないかどうかが問題です。 そこで思ったのですが、ifとcaseで速度に違いはあるのか?ということでした。

普通に考えれば演算子がifは==で比較して、caseは===で、とか、そもそもの比較対象によって速度は変わるので一概に言えないのではないだろうか、というのが自分の考えです。 それでも百聞は一見にしかずだろ、ということでやってみます。

あ、その前にググってみたらRubyのifとcaseでは、どちらが速いかこちらですでにやってました。 でも、バージョンも書いてないし、一応試してみます。

a="d"
n=1000000
 
st=Time.now
n.times{
    if a=="a"
    elsif a=="b"
    elsif a=="c"
    else end
}
puts "if Times: #{Time.now-st}s"
 
st=Time.now
n.times{
    case a
    when "a"
    when "b"
    when "c"
    else
    end
}
puts "case Times: #{Time.now-st}s"

上記のサイトのをそのまま使わせていただきます。

Ruby1.9.3で試してみます。

$ ruby --version
ruby 1.9.3p327 (2012-11-10 revision 37606) [x86_64-linux]
$ ruby sample.rb
if Times: 0.830324594s
case Times: 0.217178136s
$ ruby sample.rb
case Times: 0.194395472s
if Times: 0.66237522s

ん?上記のサイトとだいぶ違う結果が…。 まさか実行順が違う?と思って2回めの前にifとcaseの順番を変えてますが、当然そういうわけではなさそう。

じゃあRuby2.0ならどうだろう?

$ ruby --version
ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-linux]
$ ruby sample.rb
if Times: 1.780754s
case Times: 0.435103s
$ ruby sample.rb
if Times: 1.78981s
case Times: 0.431919s

おー…。

ちなみに1.9と2.0ではサーバが別物なので、そこでの数値は比較できないです。(rbenvがあるので、やろうと思えばできますが面倒…) いずれにしてもRuby1.9と2.0だとcaseのほうが3倍~4倍程度速いっぽい?

確かcaseの内部では===(case比較演算子)が使われてるはず。 じゃあif文の==をcase比較演算子に書き換えたら数値が近づくかな?と思い試してみました。

a="d"
n=1000000

st=Time.now
n.times{
    if a==="a" # ===に変えました
    elsif a==="b" # ===に変えました
    elsif a==="c" # ===に変えました
    else end
}
puts "if Times: #{Time.now-st}s"

st=Time.now
n.times{
    case a
    when "a"
    when "b"
    when "c"
    else
    end
}

$ ruby sample.rb
if Times: 2.087001s
case Times: 0.425709s
$ ruby sample.rb
if Times: 2.009104s
case Times: 0.435917s

さっきの1.8sくらいから0.2sくらい悪化してますけど!? まぁ、case比較演算子のほうが型までみたり、時間がかかるイメージはありますが…じゃあなんでcaseのほうが速い?

と、謎は謎のままです。 何事も自分で計測して確かめるのが一番ですね。(無難なまとめ)