2012-03-13 8 views
5

weakrefモジュールの公式のPythonのドキュメントによると、「弱参照の主な用途は、大きなオブジェクトを保持するキャッシュまたはマッピングを実装することです。そこで、WeakValueDictionaryを使用して、長時間実行する関数のキャッシング・メカニズムを実装しました。しかし、キャッシュ内の値は、実際に再び使用されるまでそこにとどまることはありませんでしたが、ほとんど毎回再計算する必要がありました。 WeakValueDictionaryに格納されている値へのアクセスの間に強い参照がないため、GCはそれらを取り除きました(メモリに問題は全くありませんでしたが)。WeakValueDictionaryをキャッシュに使用するときのGCの問題

ここで、キャッシュを実装するために弱いリファレンスを使用することになっていますか? GCが弱い参照を削除しないように強い参照を明示的に保持すると、最初にWeakValueDictionaryを使用する点はありません。 GCには、メモリが不足している(または何らかのしきい値を超えている)場合にのみ、参照が全くないものと弱いもののすべてを削除するオプションがあるはずです。そんなことはありますか?あるいは、この種のキャッシュにはより良い戦略がありますか?

答えて

3

weakrefモジュールを使用してキャッシュを実装する方法の例を使用して、お問い合わせにお答えします。キャッシュの弱い参照はweakref.WeakValueDictionaryに、強い参照はcollections.dequeに、maxlenというプロパティは保持しているオブジェクトの数を制御するため、キャッシュの弱い参照を保持します。関数クロージャスタイルで実装:それは容量に達すると

import weakref, collections 
def createLRUCache(factory, maxlen=64): 
    weak = weakref.WeakValueDictionary() 
    strong = collections.deque(maxlen=maxlen) 

    notFound = object() 
    def fetch(key): 
     value = weak.get(key, notFound) 
     if value is notFound: 
      weak[key] = value = factory(key) 
     strong.append(value) 
     return value 
    return fetch 

dequeオブジェクトは、単に古いエントリへの参照を落とし、最後maxlenエントリを維持します。古いエントリが削除され、Pythonによってガベージコレクトされると、WeakValueDictionaryはそれらのキーをマップから削除します。したがって、2つのオブジェクトの組み合わせは、maxlenエントリのみをLRUキャッシュに保持するのに役立ちます。

class Silly(object): 
    def __init__(self, v): 
     self.v = v 

def fib(i): 
    if i > 1: 
     return Silly(_fibCache(i-1).v + _fibCache(i-2).v) 
    elif i: return Silly(1) 
    else: return Silly(0) 
_fibCache = createLRUCache(fib) 
0

少なくともCPython 2.7および3.0では、この制限を克服する方法はないようです。

)(溶液createLRUCacheに反映:

をcreateLRUCache(工場、maxlenを= 64)とのソリューションは、私の期待と罰金ではありません。 'maxlen'へのバインディングの考え方は、私が避けたいものです。ここでは、スケーラビリティのない定数を指定したり、ヒューリスティックを作成したりして、この定数やそのホストのメモリ制限に適した定数を決めることができます。

私はGCではないすぐWeakValueDictionaryから参照されていない値を排除する希望

が、condition is used for regular GC上:

割り当ての数を引い割り当て解除の数がthreshold0よりを超えると、収集が開始されます。

関連する問題