プログラム中で、ちょっとしたキャッシュを作りたい場合。もちろんメソッドを用意してもいいのですが、再利用性が低かったり、ちょっと大袈裟感があったりする場合も。
def foo
%(a b c b a d).each do |id|
puts sample_item(id)
end
end
def sample_item id
@sample_cache[id] ||= Sample.find(id)
end
そんな時には、Hashのdefault_procを使うと簡易的に代替できます。
def foo
sample_cache = {}
sample_cache.default_proc = proc do |hash, key|
hash[key] = Sample.find(key)
end
%(a b c b a d).each do |id|
puts sample_cache[id]
end
end
コンストラクタにブロックを渡すのでもOK。
def foo
sample_cache = Hash.new{|hash, key|
hash[key] = Sample.find(key)
}
%(a b c b a d).each do |id|
puts sample_cache[id]
end
end
一応、レンスポンス的にもこちらの方が速い。
benchmark
require 'benchmark'
class TestClass
def initialize keys, cycles
@keys = keys
@cycles = cycles
@cache = {}
end
def get_data i
@cache[i] ||= Time.now
end
def test1
ret = {}
(1..@keys).cycle(@cycles){|i| ret[i] = get_data(i)}
end
def test2
ret = {}
cache = Hash.new{|h,k| h[k]=Time.now}
(1..@keys).cycle(@cycles){|i| ret[i] = cache[i]}
end
end
t = TestClass.new(10000, 1000)
Benchmark.bm do |x|
x.report { t.test1 }
x.report { t.test2 }
x.report { t.test2 }
x.report { t.test1 }
end
result
user system total real
2.860000 0.010000 2.870000 ( 2.866910)
2.150000 0.000000 2.150000 ( 2.162081)
2.180000 0.000000 2.180000 ( 2.188632)
2.980000 0.000000 2.980000 ( 2.983547)