Python3.3のLRU キャッシュには、O(1) の挿入、削除、および検索があります。
この設計では、エントリの循環的な二重リンク リスト (古いものから新しいものへと配置) とハッシュ テーブルを使用して、個々のリンクを見つけます。キャッシュ ヒットは、ハッシュ テーブルを使用して関連するリンクを見つけ、それをリストの先頭に移動します。キャッシュ ミスにより、最も古いリンクが削除され、リンク リストの先頭に新しいリンクが作成されます。
これは、33 行の非常に基本的な Python の単純化された (ただし高速な) バージョンです (単純な辞書操作とリスト操作のみを使用)。Python2.0 以降 (または PyPy、Jython、Python3.x) で動作します。
class LRU_Cache:
def __init__(self, original_function, maxsize=1024):
# Link structure: [PREV, NEXT, KEY, VALUE]
self.root = [None, None, None, None]
self.root[0] = self.root[1] = self.root
self.original_function = original_function
self.maxsize = maxsize
self.mapping = {}
def __call__(self, *key):
mapping = self.mapping
root = self.root
link = mapping.get(key)
if link is not None:
link_prev, link_next, link_key, value = link
link_prev[1] = link_next
link_next[0] = link_prev
last = root[0]
last[1] = root[0] = link
link[0] = last
link[1] = root
return value
value = self.original_function(*key)
if len(mapping) >= self.maxsize:
oldest = root[1]
next_oldest = oldest[1]
root[1] = next_oldest
next_oldest[0] = root
del mapping[oldest[2]]
last = root[0]
last[1] = root[0] = mapping[key] = [last, root, key, value]
return value
if __name__ == '__main__':
p = LRU_Cache(ord, maxsize=3)
for c in 'abcdecaeaa':
print(c, p(c))
Python 3.1 から、OrderedDictにより LRU キャッシュの実装がさらに簡単になります。
from collections import OrderedDict
class LRU_Cache:
def __init__(self, original_function, maxsize=1024):
self.original_function = original_function
self.maxsize = maxsize
self.mapping = OrderedDict()
def __call__(self, *key):
mapping = self.mapping
try:
value = mapping[key]
mapping.move_to_end(key)
except KeyError:
value = self.original_function(*key)
if len(mapping) >= self.maxsize:
mapping.popitem(False)
mapping[key] = value
return value