Rubyが遅いのは本当にBoxingのせいか?
HotRubyがYARVより速いのはBoxingのせい、ということのようです。ベンチマークと言うのが何をさしているのか分かりませんが、とりあえずHotRubyのサイトのStringのベンチマークを対象として考えます。
それはこんなベンチマークです。
startTime = Time.new.to_f sum = "" 50000.times{|e| sum += e.to_s} endTime = Time.new.to_f puts (endTime - startTime).to_s + ' sec'
本当にBoxingのせいなんでしょうか?
結論から言うとそんなことはないのではないか?って感じです。
もともとRubyのプリミティブ型はソースコード中で特別扱いされていたし(1.8しか見てませんが)、C言語レベルで考えられる中ではそこそこ高速化してました。
HotRubyのサイトにあるStringのベンチマークは海外のブログでも取り上げられて、その時にツッコミを喰らってます。
http://ejohn.org/blog/ruby-vm-in-javascript/
with "<<" and you'll see that Ruby is 10x faster than the HotRuby version.
実際、+=を<<に変えるとRubyは爆速です。(Rubyは1.8.6を使っています)
#+=のとき 7.21914291381836 sec # <<のとき 0.135228872299194 sec
なんだか、桁が違います。
ただ、<<は破壊的なメソッドなので、YARVのオブジェクト生成に時間がかかる可能性は否定できません。
ついでに、下記のようにしても速いです。
startTime = Time.new.to_f sum = " "*(40000*5+9000*4+900*3+90*2+10) i=0 50000.times{|e| e_str=e.to_s; sum[i...i+e_str.length]=e_str; i+=e_str.length } endTime = Time.new.to_f puts (endTime - startTime).to_s + ' sec' #実行結果 0.345652103424072 sec
領域を最初に確保してあげると、それなりの速さになります。e.to_sでStringを大量に生成しても遅くならないわけですから、Stringの生成で遅くなっている気がしません。
さらに、HotRubyのサイトにあるスクリプト(String#+を使う)場合に、合計50000回実行するのを10000回ごとに区切って実行時間を表示してみます。
#実行結果 0.266942024230957 sec #最初の10000回 0.818481922149658 sec #10000-20000回 1.30647802352905 sec #20000-30000回 1.76571893692017 sec #30000-40000回 2.35495710372925 sec #40000-50000回
だんだんと時間がかかってきているということは、結局はString#newで他よりも大きい範囲のメモリコピーが多発してしまっている、ということのような気がします。
さらにちなみに、同じものをHotRuby上で実行するとこうなります。
0.7890000343322754 sec 0.7769999504089355 sec 0.7820000648498535 sec 0.7790000438690186 sec 0.7779998779296875 sec
時間が一定です。すごくおもしろいですね。