Module: When::Parts::MethodCash
- Included in:
- Coordinates::Temporal, Ephemeris::Formula
- Defined in:
- lib/when_exe/parts/method_cash.rb
Overview
メソッドの実行結果をキャッシュし処理の高速化を行う
fn というメソッドをキャッシュ化
* fn ではなく fn_ を定義しておく
* fn メソッドが呼ばれると fn_ を実行し、{引数=>戻り値} を Hash に記憶する
* 同じ引数で再度 fn メソッドが呼ばれると Hash から戻り値を取り出して返す
a_to_b と b_to_a という互いに逆関数のメソッドをキャッシュ化
* a_to_b ではなく a_to_b_ , b_to_a ではなく b_to_a_ を定義しておく
* a_to_b メソッドが呼ばれると a_to_b_ を実行し、{引数=>戻り値}, {戻り値=>引数}を Hash に記憶する
* 同じ引数で再度 a_to_b メソッドが呼ばれると Hash から戻り値を取り出して返す
* b_to_a メソッドが呼ばれ Hash に戻り値があれば Hash から戻り値を取り出して返す
特記事項
Argument identification
The eql? method of When::TM::(Temporal)Position is not overridden.
It seems that the cost of identification of the argument exceeds the merit of the method cash.
I do not recommend applying the methodcash to the method which takes
When::TM::(Temporal)Position as an argument.
Multi-thread critical situation
There is a problem in consistency of hash when this function is used in multi-thread environment.
If the initialize method sets Mutex in instance variable @_m_cash_lock_,
this function gives up use of hash in the critical situation.
class Foo
include MethodCash
def initialize
...
@_m_cash_lock_ = Mutex.new
...
end
end
参考 http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/47663
Constant Summary collapse
- Escape =
{:to_str => true, :to_ary => true, :to_hash => true}
Class Attribute Summary collapse
-
.direct ⇒ Boolean
‘_’ で終わるメソッドをキャッシュせずに毎回計算するか否か.
Class Method Summary collapse
-
._setup_(options = {}) ⇒ void
When::Parts::MethodCash のグローバルな設定を行う.
-
._setup_info ⇒ Hash
設定情報を取得する.
-
.escape(method) ⇒ boolean
method_missing メソッドを forward するか否か.
Instance Method Summary collapse
-
#method_missing(name, *args, &block) ⇒ void
最初に発生する method_missing で、キャッシュ機能を登録する.
- #method_missing_ ⇒ Object
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args, &block) ⇒ void
This method returns an undefined value.
最初に発生する method_missing で、キャッシュ機能を登録する
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/when_exe/parts/method_cash.rb', line 136 def method_missing(name, *args, &block) return method_missing_(name, *args, &block) unless respond_to?("#{name}_", true) return send("#{name}_", *args, &block) if MethodCash.direct if ((name.to_s =~ /\A(_*)(.+?)_to_(.+)\z/) && respond_to?("#{$1}#{$3}_to_#{$2}_", true)) prefix, from, to = $~[1..3] begin if @_m_cash_lock_ return send("#{prefix}#{from}_to_#{to}_", *args, &block) unless @_m_cash_lock_.try_lock unlock = "ensure ; @_m_cash_lock_.locked? && @_m_cash_lock_.unlock" end [[from, to],[to, from]].each do |pair| a, b = pair lock = @_m_cash_lock_ ? " return #{prefix}#{a}_to_#{b}_(*args) unless @_m_cash_lock_.try_lock" : '' instance_eval %Q{ def #{prefix}#{a}_to_#{b}(*args) key = _key_simplefy(args) inv = @_m_cash_["#{prefix}#{a}_to_#{b}"][key] return inv if inv begin #{lock} inv = #{prefix}#{a}_to_#{b}_(*args) @_m_cash_["#{prefix}#{b}_to_#{a}"][_key_simplefy(inv)] = args @_m_cash_["#{prefix}#{a}_to_#{b}"][key] = inv return inv #{unlock} end rescue ThreadError end } end key = _key_simplefy(args) inv = send("#{prefix}#{from}_to_#{to}_", *args) @_m_cash_ ||= Hash.new {|hash,key| hash[key]={}} @_m_cash_["#{prefix}#{to}_to_#{from}"][_key_simplefy(inv)] = args @_m_cash_["#{prefix}#{from}_to_#{to}"][key] = inv return inv ensure begin @_m_cash_lock_ && @_m_cash_lock_.locked? && @_m_cash_lock_.unlock rescue ThreadError end end else begin respond = respond_to?("#{name}_setup", true) setup = respond ? "#{name}_setup(key, *args)" : "(@_m_cash_[\"#{name}\"][key] = #{name}_(*args))" if @_m_cash_lock_ return send("#{name}_", *args, &block) unless @_m_cash_lock_.try_lock lock = " return #{name}_(*args) unless @_m_cash_lock_.try_lock" unlock = "ensure ; @_m_cash_lock_.locked? && @_m_cash_lock_.unlock" end instance_eval %Q{ def #{name}(*args) key = _key_simplefy(args) ret = @_m_cash_["#{name}"][key] return ret if ret begin #{lock} return #{setup} #{unlock} end rescue ThreadError end } key = _key_simplefy(args) @_m_cash_ ||= Hash.new {|hash,key| hash[key]={}} if respond return send("#{name}_setup", key, *args) else return(@_m_cash_["#{name}"][key] ||= send("#{name}_", *args)) end ensure begin @_m_cash_lock_ && @_m_cash_lock_.locked? && @_m_cash_lock_.unlock rescue ThreadError end end end end |
Class Attribute Details
.direct ⇒ Boolean
‘_’ で終わるメソッドをキャッシュせずに毎回計算するか否か
66 67 68 |
# File 'lib/when_exe/parts/method_cash.rb', line 66 def direct @direct end |
Class Method Details
._setup_(options = {}) ⇒ void
Note:
When::TM::Calendar クラスの一部はキャッシュ使用を前提としているため :direct=>true では動作しません
This method returns an undefined value.
When::Parts::MethodCash のグローバルな設定を行う
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/when_exe/parts/method_cash.rb', line 80 def _setup_(={}) @_setup_info = @direct = [:direct] case [:escape] when true instance_eval %Q{ def escape(method) true end } when Hash @escape = Escape.merge([:escape]) instance_eval %Q{ def escape(method) @escape[method] end } else instance_eval %Q{ def escape(method) Escape.key?(method) end } end end |
._setup_info ⇒ Hash
設定情報を取得する
110 111 112 |
# File 'lib/when_exe/parts/method_cash.rb', line 110 def _setup_info @_setup_info ||= {} end |
.escape(method) ⇒ boolean
method_missing メソッドを forward するか否か
120 121 122 |
# File 'lib/when_exe/parts/method_cash.rb', line 120 def escape(method) Escape.key?(method) end |
Instance Method Details
#method_missing_ ⇒ Object
125 |
# File 'lib/when_exe/parts/method_cash.rb', line 125 alias :method_missing_ :method_missing |