PerlerのRuby日記

Rubyとか

evalよりinsntance_variable_setのほうが10倍速かった話

コンストラクタで、インスタンス変数を初期化する際に引数があればそれを、なければデフォルト値を入れたかった。


class Hoge
  attr_accessor :foo, :bar, :baz
  DEFAULT = { 
    :foo => 'foo',
    :bar => 'baz',
    :baz => 'baz',
  }
  def initialize(opt = {})
    DEFAULT.each { |key, val|
      instance_variable_set("@#{key}", opt[key] || val)    # ここと
    }
  end 
end

class Fuga
  attr_accessor :foo, :bar, :baz
  DEFAULT = { 
    :foo => 'foo',
    :bar => 'baz',
    :baz => 'baz',
  }
  def initialize(opt = {}) 
    DEFAULT.each { |key, val|
      eval "@#{key} = opt[:#{key}] || val"     # ここ
    }
  end
end


require "benchmark"

Benchmark.bmbm { |x| 
  x.report('instance_variable_set') {
    (1..1_000_000).each {
      Hoge.new(:foo => 'FOO')
    }
  }                                                                                                                     
  x.report('eval') {
    (1..1_000_000).each {
      Fuga.new(:foo => 'FOO')
    }
  }
}
Rehearsal ---------------------------------------------------------
instance_variable_set   5.570000   0.010000   5.580000 (  5.590429)
eval                   50.110000   0.060000  50.170000 ( 50.348506)
----------------------------------------------- total: 55.750000sec

                            user     system      total        real
instance_variable_set   6.010000   0.000000   6.010000 (  6.011255)
eval                   51.020000   0.040000  51.060000 ( 51.103497)

10倍くらいinstance_variable_setの方が速かった。

というかご多分に漏れず、evalが遅いのか。