読者です 読者をやめる 読者になる 読者になる

WHITELEAF:Kindle応援サイト

KindleでWEB小説を読もう! Narou.rb 公開中

access hash

Ruby Rubyベンチ

Hash をアクセスする際に Fixnum, Symbol, String を使う場合の比較です。Hash ではなく Array を使った結果もつけておきます。

require "benchmark"

class Test
  def initialize
    @num_table = {}
    @sym_table = {}
    @str_table = {}
    @array = []
    100.times { |i|
      @num_table[i] = i
      @sym_table[i.to_s.intern] = i
      @str_table[i.to_s] = i
      @array[i] = i
    }
  end

  def test_num(key)
    @num_table[key]
  end

  def test_sym(key)
    @sym_table[key]
  end

  def test_str(key)
    @str_table[key]
  end

  def test_array(key)
    @array[key]
  end
end

t = Test.new
Benchmark.bm { |bm|
  bm.report("num") {
    10000000.times {
      t.test_num(50)
    }
  }
  bm.report("sym") {
    10000000.times {
      t.test_sym(:"50")
    }
  }
  bm.report("str") {
    10000000.times {
      t.test_str("50")
    }
  }
  bm.report("arr") {
    10000000.times {
      t.test_array(50)
    }
  }
}
ruby 1.9.2dev (2010-04-27 trunk 27505) [i386-mingw32]
      user     system      total        real
num  2.297000   0.000000   2.297000 (  2.312500)
sym  2.391000   0.000000   2.391000 (  2.390625)
str  4.031000   0.000000   4.031000 (  4.046875)
arr  1.984000   0.000000   1.984000 (  1.984375)
ruby 1.8.7 (2010-06-23 patchlevel 299) [i386-mswin32]
      user     system      total        real
num  7.375000   0.000000   7.375000 (  7.406250)
sym  7.328000   0.000000   7.328000 (  7.343750)
str 10.266000   0.000000  10.266000 ( 10.281250)
arr  7.031000   0.000000   7.031000 (  7.031250)

Fixnum は定数によるアクセスを想定しています。
Fixnum もしくは Symbol によるアクセスが最速です。String を key にするのは速度低下を招くので、Symbol に変換(String#intern)するのが良いでしょう。

*追記2*
テストコードが間違ってました('A` ) 修正しました。

*追記*
JRuby 1.5.1 でも試してみました。

jruby 1.5.1 (ruby 1.8.7 patchlevel 249) (2010-06-06 f3a3480) (Java HotSpot(TM)
Client VM 1.6.0_20) [x86-java]
      user     system      total        real
num  3.156000   0.000000   3.156000 (  3.140000)
sym 10.719000   0.000000  10.719000 ( 10.719000)
str  4.640000   0.000000   4.640000 (  4.640000)
arr  2.719000   0.000000   2.719000 (  2.719000)

Ruby 1.9.2 に肉薄する結果です。Symbol 以外は。
どうも JRuby は :"50" と Symbol を作ってる部分が遅いみたいなので、

  bm.report("sym") {
    sym = :"50"
    10000000.times {
      t.test_sym(sym)
    }
  }

と事前に key を作成しておくことで、

sym  4.266000   0.000000   4.266000 (  4.266000)

と非常に速度が改善されました。