2012-01-03 80 views
1

我有一個圖像目錄的順序。典型地,我的代碼將被使用從圖像的順序的子集的數據(例如圖像5-10),以及用於訪問這些幼稚選項有:Python中昂貴對象的智能緩存

  1. 與在需要時加載圖像的方法創建一個包裝對象並讀取我的數據(例如像素值)。這隻有很少的內存開銷,但會很慢,因爲它需要每次加載每個圖像。

  2. 將所有圖像存儲在內存中。這會很快,但顯然我們可以存儲多少圖片是有限制的。

我想找到:

  • 一些方法,通過它我可以定義如何讀取相應的索引或路徑,圖像,然後讓我來接,說magic_image_collection[index]沒有我不必擔心它是否會返回內存中的對象或重新讀取它。這將理想地保留適當的圖像或最近訪問的圖像在內存中。

回答

5

您可以擴展默認字典,並使用__missing__方法來調用加載功能,如果關鍵是丟失:(裝入只在關鍵尚不存在發生)

class ImageDict(dict): 
    def __missing__(self, key): 
     self[key] = img = self.load(key) 
     return img 
    def load(self, key): 
     # create a queue if not exist (could be moved to __init__) 
     if not hasattr(self, '_queue'): 
      self._queue = [] 
     # pop the oldest entry in the list and the dict 
     if len(self._queue) >= 100: 
      self.pop(self._queue.pop(0)) 
     # append this key as a newest entry in the queue 
     self._queue.append(key) 
     # implement image loading here and return the image instance 
     print 'loading', key 
     return 'Image for %s' % key 

和輸出

>>> d = ImageDict() 
>>> d[3] 
loading 3 
'Image for 3' 
>>> d[3] 
'Image for 3' 
>>> d['bleh'] 
loading bleh 
'Image for bleh' 
>>> d['bleh'] 
'Image for bleh' 

一個演變將是t o只存儲字典中的最後一個元素,並清除最舊的條目。您可以通過保存用於排序的鍵列表來實現它。

+2

擺脫'__getitem__'並將加載重命名爲'__missing__',你應該沒問題。 – PaulMcG 2012-01-03 15:50:13

+1

您在'__missing__'中所做的所有事情都是爲鍵返回適當的值,或者引發異常。調用'__missing__'的'dict'代碼將負責更新字典(您的類繼承自此)。要添加對「最後n個元素」的支持,請將鍵列表添加爲成員,並將該鍵添加到'__missing__'列表的末尾。當列表超過n時,從列表中彈出最早的第(0)個鍵。 – PaulMcG 2012-01-03 16:05:57

+0

謝謝保羅,不知道'__missing__',非常好! – tito 2012-01-03 17:28:28

2

Weakrefs不是你想要的 - weakrefs是一種引用項目的方法,它允許垃圾收集器收集(即銷燬)指示對象,如果只有弱指令存在。換句話說,如果您只創建並存儲了某些對象的弱參數,則很可能會很快收集垃圾,並且您不會從中受益。

我會選擇上面的選項#1。在現代操作系統上,操作系統維護最近訪問過的文件(或其中的一部分)的內存緩存,這意味着你將不得不承擔從磁盤加載文件一次的成本,但在此之後,後續訪問該文件將會像應用程序中的內存一樣快(或幾乎如此)。 FS緩存通常是LRU風格的緩存,所以經常訪問的項目往往會留在內存中,而不常訪問的項目往往會被逐出(如果需要,隨後會從磁盤加載)。在大多數情況下,依靠操作系統實現這種邏輯就足夠了,而不是自己編寫(特別是因爲您不必編寫和維護代碼來執行此操作!)

+0

感謝您對弱點的澄清。我會嘗試#1和@tito的想法。 – YXD 2012-01-03 15:39:36