MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Python:Erstellen eines LRU-Cache

Der LRU-Cache in Python3.3 hat O(1) Insertion, Deletion und Search.

Das Design verwendet eine kreisförmige, doppelt verknüpfte Liste von Einträgen (geordnet vom ältesten zum neuesten) und eine Hash-Tabelle, um einzelne Links zu lokalisieren. Cache-Treffer verwenden die Hash-Tabelle, um den relevanten Link zu finden und an den Kopf der Liste zu verschieben. Cache-Mißerfolge löschen den ältesten Link und erstellen einen neuen Link am Anfang der verknüpften Liste.

Hier ist eine vereinfachte (aber schnelle) Version in 33 Zeilen von sehr einfachem Python (unter Verwendung nur einfacher Wörterbuch- und Listenoperationen). Es läuft auf Python2.0 und höher (oder PyPy oder Jython oder 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))

Ab Python 3.1 OrderedDict macht es noch einfacher, einen LRU-Cache zu implementieren:

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