2010-12-14 21 views
7

tengo alrededor 6,00,000 entries in MongoDB en el siguiente formato:Python: la construcción de una memoria caché LRU

feature:category:count 

donde

  • función podría ser cualquier palabra,
  • categoría es positivo o negativo y
  • cuenta indica cuántas veces se produjo una característica en un documento para esa categoría.

Quiero almacenar en memoria caché las 1000 tuplas superiores, digamos para no consultar la base de datos cada vez.

¿Cómo se puede construir una memoria caché LRU en Python? ¿O hay alguna solución conocida para esto?

Respuesta

3

Python 3.2 functools incluye un LRU cache. Usted podría fácilmente tomar una pepita de repo, comprobar si tiene que ajustarla para trabajar con Python 2 (no debería ser demasiado difícil - tal vez usando itertools en lugar de ciertas instrucciones internas - pregunte si necesita ayuda) y listo. Sin embargo, debe envolver la consulta en un invocable y asegurarse de que depende de los argumentos de la función (hashable).

+0

Esto parece interesante, pero ¿cómo puedo obtenerlo del repositorio? No sé cómo hacer eso \ – daydreamer

+0

@learner: la forma más fácil sería copiarlo desde el archivo al que me he vinculado. – delnan

+0

he intentado pero cuando intento importar functools arroja functools error >>> importación Rastreo (llamada más reciente pasado): Archivo "", línea 1, en Archivo "functools.py", línea 151 no local hits, pierde ^ SyntaxError: sintaxis no válida Error en sys.excepthook: – daydreamer

5

Además de la versión incluida en Python 3.2, hay recetas de caché LRU en Python Cookbook incluyendo these del desarrollador de Python Core Raymond Hettinger.

17

El LRU cache en Python3.3 tiene O (1) inserción, eliminación y búsqueda.

El diseño utiliza una lista de entradas circular doblemente unida (dispuestas del más antiguo al más nuevo) y una tabla hash para localizar enlaces individuales. Los hits de caché usan la tabla hash para encontrar el enlace relevante y moverlo al encabezado de la lista. La caché falla al eliminar el enlace más antiguo y crear un nuevo enlace en la cabecera de la lista vinculada.

Aquí hay una versión simplificada (pero rápida) en 33 líneas de Python muy básico (usando solo operaciones simples de diccionario y lista). Se ejecuta en Python2.0 y más tarde (o PyPy o Jython o 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)) 
1

También hay backports de la versión pitón 3.3 de lru_cache como this que se ejecuta en pitón 2.7. Si está interesado en dos capas de almacenamiento en caché (si no está almacenado en caché en la instancia, comprobará una caché compartida), he creado lru2cache en función del respaldo de lru_cache.

Cuestiones relacionadas