クラスの探索
文字列からクラスに変換するのに今までは、ObjectSpace.each_objectを使っていたけれど、これが結構遅い。
# 旧コード:遅いけれど、柔軟 def find_by_each(name) ObjectSpace.each_object(Class) do|klass| if klass.to_s.downcase == name.downcase return klass end end end
そこで、文字列をevalするようにしてみた。ただし単純にevalするだけだと不便なので、foo::bar::bazをFoo::Bar::Bazのように変換するようにしてみた。
# 新コード:速いけれど、柔軟性はあまりない def find_by_eval(name) eval name.split('::').map{|x| x.capitalize }.join('::') end
そして、次のようなコードを用意して速度を比較してみた。
100.times{ find_by_each 'string' } 100.times{ find_by_eval 'string' }
$ ruby -r profile find_obj.rb 2>&1 | grep 'find_by_' 0.28 6.88 0.02 100 0.20 0.50 Object#find_by_eval 0.00 7.04 0.00 100 0.00 62.90 Object#find_by_each
ちなみに左から、
- 全体時間のパーセンテージ
- 全体時間の総和(単位は秒)
- 正味時間の総和(秒)
- 呼び出された回数
- 1回の呼び出し当たりの平均正味時間(ミリ秒)
- 1回の呼び出し当たりの平均全体時間(ミリ秒)
- メソッド名
となっている。
つまり、evalを使ったほうが100倍以上速くなっている。ただし、LongNameFileのように途中に大文字が現れるクラスには対応できなくなった。