効率

「ちょっと気になったので、実験してみた。」

わざわざクラスを定義するほどでもないなぁ…と思った時に気軽に Hash を使っているのだが、アクセス速度が気になったので、ちょっと実験してみた。

--- foo.rb
#!/usr/bin/env ruby

Max = 50000000

class Foo1
  attr_accessor :f1
end

obj1 = Foo1.new
obj2 = {:f1=>nil}

puts "[0] utime = #{Process.times.utime}"

(1..Max).each {|item| obj1.f1 = item}
puts "[1] utime = #{Process.times.utime}"

(1..Max).each {|item| obj2[:f1] = item}
puts "[2] utime = #{Process.times.utime}"

for item in 1..Max do obj1.f1 = item end
puts "[3] utime = #{Process.times.utime}"

for item in 1..Max do obj2[:f1] = item end
puts "[4] utime = #{Process.times.utime}"

1, 3 がアクセサーで 2, 4 が Hash。1,2 がイテレーターで 3,4 が一般的なループ。

  1. アクセサー & イテレータ
  2. アクセサー & ループ
  3. Hash & イテレータ
  4. Hash & ループ

実行結果は次の通り。(最後の列はエクセルで追加。)

ラベル 累積 時間
[0] utime = 0.01 sec
[1] utime = 49.58 sec 49.57 sec
[2] utime = 101.82 sec 52.24 sec
[3] utime = 144.56 sec 42.74 sec
[4] utime = 190.00 sec 45.44 sec

これだけの処理時間で数秒の差なので、Ruby ではアクセサーと Hash の間で有意な差はない考えて良さそう。Ruby の内部のことまでは分からないけど、似たような仕組みで管理してそうな気はする。まあ、パフォーマンスを理由にして実装を選択する必要はなさそうだ。

最近、ループはめっきり使わなくなってしまったのだけど、イテレーターよりもループの方が早いのはちょっと残念。