LoginSignup
6
6

More than 5 years have passed since last update.

[Ruby]Hashのdefault_procで簡易キャッシュ

Posted at

プログラム中で、ちょっとしたキャッシュを作りたい場合。もちろんメソッドを用意してもいいのですが、再利用性が低かったり、ちょっと大袈裟感があったりする場合も。

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)
6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6