Ruby Meta Programming: define_method or class_eval
今日はMatt Aimonettiのblogでruby meta programmingの実行効率について議論しているのを見て、ついてみましたが、いろいろなことを学びました.大まかに言えば、まずMattは簡単な計算時間のDSLクラスを書きました.
このクラスは簡単です.Numericクラスに時間に関するいくつかの方法を追加します.これにより、類似のコードを使用して時間を計算できます.たとえば、次のようにします.
コードは簡単ですが、Mattの使用に注意してください.
そして彼はdefineを利用してmethod方式でTimeDSLを実現するクラス(説明の便宜上、省略しました)
彼はこの2つのbenchmarkのテストデータを発表し、rubyのmeta programmingは基本的に正常な方法より3倍ほど遅いと結論した(私自身のテストデータは2倍ぐらいだ)
この結論はすぐに多くの人の議論を引き起こし,最後にWycatsは改善案を提出した.
新しいクラスの実行効率が通常の方法で定義されたクラスに迫るのは,ほとんど差がないと言える.その原因を究明するmethodは実行するためにProcを作成する必要がありますがclass_evalとruby自身の実行方式には何の違いもなく,実行を直接解釈している.
最後の結論は、できればclassを使うことです.义齿
添付ファイルの図面をどのように貼るか分かりませんが、添付ファイルを見てください.ソースコードも含まれています.
テスト全体がjruby 1.1.3で合格しました
参考になる
http://railsontherun.com/2008/6/18/about-metaprogramming-speed
module TimeDSL
def second
self * 1
end
alias_method :seconds, :second
def minute
self * 60
end
alias_method :minutes, :minute
def hour
self * 3600
end
alias_method :hours, :hour
def day
self * 86400
end
alias_method :days, :day
def week
self * 604800
end
alias_method :weeks, :week
def month
self * 2592000
end
alias_method :months, :month
def year
self * 31471200
end
alias_method :years, :year
end
Numeric.send :include, TimeDSL
このクラスは簡単です.Numericクラスに時間に関するいくつかの方法を追加します.これにより、類似のコードを使用して時間を計算できます.たとえば、次のようにします.
1.hours + 20.minutes # => 20
3.days + 5.hours # => 3 5
2.years + 10.months # =>
コードは簡単ですが、Mattの使用に注意してください.
Numeric.send :include, TimeDSL
法はNumericクラスにTimeDSLというモジュールを追加した.そして彼はdefineを利用してmethod方式でTimeDSLを実現するクラス(説明の便宜上、省略しました)
module BadMetaTimeDSL
{:second => 1,
:minute => 60,
:hour => 3600,
:day => [24,:hours],
:week => [7,:days],
:month => [30,:days],
:year => [364.25, :days]}.each do |meth, amount|
define_method "b_#{meth}" do
amount = amount.is_a?(Array) ? amount[0].send(amount[1]) : amount
self * amount
end
alias_method "b_#{meth}s".intern, "b_#{meth}"
end
end
Numeric.send :include, BadMetaTimeDSL
彼はこの2つのbenchmarkのテストデータを発表し、rubyのmeta programmingは基本的に正常な方法より3倍ほど遅いと結論した(私自身のテストデータは2倍ぐらいだ)
この結論はすぐに多くの人の議論を引き起こし,最後にWycatsは改善案を提出した.
module GoodMetaTimeDSL
SECOND = 1
MINUTE = SECOND * 60
HOUR = MINUTE * 60
DAY = HOUR * 24
WEEK = DAY * 7
MONTH = DAY * 30
YEAR = DAY * 364.25
%w[SECOND MINUTE HOUR DAY WEEK MONTH YEAR].each do |const_name|
meth = const_name.downcase
class_eval <<-RUBY
def g_#{meth}
self * #{const_name}
end
alias g_#{meth}s g_#{meth}
RUBY
end
end
Numeric.send :include, GoodMetaTimeDSL
新しいクラスの実行効率が通常の方法で定義されたクラスに迫るのは,ほとんど差がないと言える.その原因を究明するmethodは実行するためにProcを作成する必要がありますがclass_evalとruby自身の実行方式には何の違いもなく,実行を直接解釈している.
最後の結論は、できればclassを使うことです.义齿
添付ファイルの図面をどのように貼るか分かりませんが、添付ファイルを見てください.ソースコードも含まれています.
テスト全体がjruby 1.1.3で合格しました
参考になる
http://railsontherun.com/2008/6/18/about-metaprogramming-speed