2012-03-13 17 views
5

Theo tài liệu Python chính thức cho mô-đun weakref, "việc sử dụng chính cho các tham chiếu yếu là thực hiện bộ đệm hoặc ánh xạ giữ các đối tượng lớn, ...". Vì vậy, tôi đã sử dụng một WeakValueDictionary để thực hiện một cơ chế bộ nhớ đệm cho một chức năng chạy dài. Tuy nhiên, khi nó bật ra, giá trị trong bộ nhớ cache không bao giờ ở lại đó cho đến khi họ thực sự sẽ được sử dụng một lần nữa, nhưng cần thiết để được recomputed gần như mọi thời gian. Vì không có tham chiếu mạnh mẽ giữa các truy cập vào các giá trị được lưu trữ trong WeakValueDictionary, GC đã loại bỏ chúng (mặc dù hoàn toàn không có vấn đề với bộ nhớ).Các vấn đề với GC khi sử dụng WeakValueDictionary cho bộ đệm

Bây giờ, làm cách nào để tôi sử dụng công cụ tham chiếu yếu để triển khai bộ nhớ cache? Nếu tôi giữ tài liệu tham khảo mạnh mẽ ở đâu đó một cách rõ ràng để giữ cho GC xóa các tham chiếu yếu của tôi, thì sẽ không có điểm nào bằng cách sử dụng WeakValueDictionary ngay từ đầu. Có lẽ nên có một số tùy chọn để GC cho biết: xóa mọi thứ không có tham chiếu nào cả và mọi thứ có tham chiếu yếu chỉ khi bộ nhớ bị hết (hoặc vượt quá ngưỡng nào đó). Có cái gì đó như thế không? Hoặc có chiến lược tốt hơn cho loại bộ nhớ cache này không?

Trả lời

3

Tôi sẽ cố gắng trả lời câu hỏi của bạn bằng ví dụ về cách sử dụng mô-đun weakref để triển khai bộ nhớ đệm. Chúng tôi sẽ giữ các tham chiếu yếu của bộ nhớ cache trong một số weakref.WeakValueDictionary và các tham chiếu mạnh trong một collections.deque vì nó có thuộc tính maxlen kiểm soát số lượng đối tượng mà nó chứa. Thực hiện chức năng phong cách đóng cửa:

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 

Đối tượng deque sẽ chỉ giữ maxlen mục cuối cùng, chỉ cần thả tham chiếu đến các mục cũ khi nó đạt công suất. Khi các mục cũ bị bỏ và rác thu thập bởi python, WeakValueDictionary sẽ xóa các khóa đó khỏi bản đồ. Do đó, sự kết hợp của hai đối tượng này giúp chúng ta chỉ giữ các mục maxlen trong bộ nhớ cache LRU của chúng ta.

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

Dường như không có cách nào khắc phục giới hạn này, ít nhất trong CPython 2.7 và 3.0.

Phản ánh về giải pháp createLRUCache():

Các giải pháp với createLRUCache (nhà máy, maxlen = 64) là không tốt với mong đợi của tôi. Ý tưởng ràng buộc với 'maxlen' là điều tôi muốn tránh. Nó sẽ buộc tôi phải xác định ở đây một số hằng số không thể mở rộng hoặc tạo ra một số heuristic, để quyết định hằng số nào tốt hơn cho điều này hoặc giới hạn bộ nhớ máy chủ.

Tôi muốn GC sẽ loại bỏ các giá trị unreferenced từ WeakValueDictionary không ngay lập tức, nhưng trên condition is used for regular GC:

Khi số lượng phân bổ trừ đi số deallocations vượt threshold0, bộ sưu tập bắt đầu.

Các vấn đề liên quan