access hash
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)
と非常に速度が改善されました。