我有一個包含 20,000 個鍵的字典,字典的總大小為 150MB。我每小時通過pickle將dict轉儲到磁盤,然后在程式啟動時加載pickle檔案。這是撰寫代碼的要點
cache_copy = copy.deepcopy(self.cache)
#self.cache is the dict
pickle.dump(cache_copy, cache_file, pickle.HIGHEST_PROTOCOL)
有時我會收到以下錯誤
cache_copy = copy.deepcopy(self.cache)
File "/usr/lib/python2.7/copy.py", line 163, in deepcopy
y = copier(x, memo)
File "/usr/lib/python2.7/copy.py", line 256, in _deepcopy_dict
for key, value in x.iteritems():
RuntimeError: dictionary changed size during iteration
做這個的最好方式是什么?我想真正避免執行緒鎖定,因為它使代碼復雜。如果確實有必要,鎖定應該盡可能小/簡單,并允許一些并發性。我的代碼中有幾個約束可以幫助實作這個方向:
- 多個執行緒讀取和寫入 dict()。但是,在所有寫入中,僅添加了 (key,value) 對。(key, value) 對永遠不會被洗掉或修改
- 我愿意將資料結構從 dict() 更改為其他內容。它應該具有快速記憶體查找和寫入的功能
- 我不介意陳舊的寫作。因此,如果 dict() 有一些附加,并且我們寫入一個比它早幾秒的 dict 快照,那也沒關系。
uj5u.com熱心網友回復:
TL;DR 編輯
為避免在酸洗期間鎖定字典,請創建一個復制字典的串列:
# When you do this:
cache["new_key"] = "new_value"
# Also do this:
cache_list.append(("new_key", "new_value"))
而是腌制串列。
最好附加到cache_file而不是覆寫它。這樣,您可以cache_list.clear()在每次寫入檔案后,避免記憶體和磁盤寫入的浪費。但是當某些執行緒在酸洗后立即寫入串列時可能會出現錯誤,然后該值被clear編輯。如果這只是一個快取,也許你可以丟失一些值。如果沒有,請使用一些鎖或不clear列出。我對雙重記憶體使用不正確,因為串列沒有deepcopy資料,它只存盤 20000 個元組,每個元組有 2 個參考。
原始答案
如果您想迭代、復制或腌制您的 dict,則需要鎖定所有寫入。但是,如果您真的不想鎖定使用 dict 的執行緒并且您不介意將記憶體使用量增加一倍,我可以建議保留一個鍵值對串列(它與您的 dict 重復),一個鎖串列和對該串列的寫入佇列:
# When you do this:
cache["new_key"] = "new_value"
# Also do this:
if not list_is_locked:
cache_list.append(("new_key", "new_value"))
else:
# Write here immediately instead of waiting for list to unlock
queue.append(("new_key", "new_value"))
當腌制時間到來時,您鎖定并腌制該串列而不是字典:
list_is_locked = True
# pickle cache_list here
list_is_locked = False
cache_list.extend(queue)
queue.clear()
我不太熟悉pickle,但如果可以附加cache_file而不是覆寫它,您也可以在腌制后清除串列。這將有助于避免巨大的記憶體負擔。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/417320.html
標籤:
上一篇:使用執行緒列印arraylist時出現IllegalMonitorStateException
下一篇:使用串列時Dart隔離非常慢
