2012-03-13 2 views
5

weakref 모듈에 대한 공식 Python 설명서에 따르면 "약한 참조의 기본 용도는 대형 객체를 포함하는 캐시 또는 매핑을 구현하는 것입니다.". 그래서 WeakValueDictionary를 사용하여 장기 실행 함수에 대한 캐싱 메커니즘을 구현했습니다. 그러나 캐시에서 값이 실제로 다시 사용될 때까지 캐시에 남아 있지 않았지만 거의 언제나 다시 계산해야했습니다. WeakValueDictionary에 저장된 값에 대한 액세스 간에는 강력한 참조가 없었으므로 GC는 메모리에서 아무런 문제가 없었음에도이를 제거했습니다.캐시에 WeakValueDictionary를 사용할 때의 GC 관련 문제

이제 약한 참조 자료를 사용하여 캐시를 구현해야하는 이유는 무엇입니까? GC에서 약한 참조를 삭제하지 않도록 명시 적으로 어딘가에 유지한다면 WeakValueDictionary를 처음 사용하는 것이 아닙니다. 메모리를 다 써 버렸을 때 (또는 약간의 임계 값을 초과 할 때) 참조가 전혀없는 모든 것을 삭제하고 약한 참조가있는 모든 것을 삭제하십시오. 그런 것이 있습니까? 아니면 이런 종류의 캐시를위한 더 나은 전략이 있습니까?

답변

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 항목을 유지합니다. 이전 항목이 삭제되고 파이썬에서 가비지 수집되면 WeakValueDictionary은 해당 키를지도에서 제거합니다. 따라서 두 개체를 결합하면 LFU 캐시에 maxlen 개의 항목 만 보관할 수 있습니다.

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와 솔루션 (공장 = 64 maxlen을)은 내 기대와 잘되지 않습니다. 'maxlen'에 바인딩하는 아이디어는 내가 피하고 싶은 것입니다. 여기에 확장 불가능 상수를 지정하거나 일부 경험칙을 작성하여이 상수 또는 호스트 메모리 한계에 대해 더 나은 상수를 결정하도록합니다.

내가 GC가되지 바로 WeakValueDictionary에서 참조되지 않은 값을 제거하는 것입니다 선호

하지만 condition is used for regular GC에 :

할당 수를 뺀 할당 취소의 수는 threshold0을 초과 모음이 시작됩니다.

관련 문제