2010-11-18 9 views
5

Estoy detrás de un contenedor seguro de subprocesos de Python donde los valores se eliminan automáticamente después de un tiempo. ¿Existe tal clase?contenedor donde los valores caducan en python

+3

posible duplicar: http://stackoverflow.com/questions/3927166/automatically-expiring-variable – mouad

+0

Estoy buscando un hilo s clase afe con tiempos de espera para cada valor. Ese ejemplo usa una lista y un tiempo de espera global. – hoju

Respuesta

5

Aquí es una versión segura del hilo de ExpireCounter:

import datetime 
import collections 
import threading 

class ExpireCounter: 
    """Tracks how many events were added in the preceding time period 
    """ 

    def __init__(self, timeout=1): 
     self.lock=threading.Lock()   
     self.timeout = timeout 
     self.events = collections.deque() 

    def add(self,item): 
     """Add event time 
     """ 
     with self.lock: 
      self.events.append(item) 
      threading.Timer(self.timeout,self.expire).start() 

    def __len__(self): 
     """Return number of active events 
     """ 
     with self.lock: 
      return len(self.events) 

    def expire(self): 
     """Remove any expired events 
     """ 
     with self.lock: 
      self.events.popleft() 

    def __str__(self): 
     with self.lock: 
      return str(self.events) 

que puede ser utilizado como esto:

import time 
c = ExpireCounter() 
assert(len(c) == 0) 
print(c) 
# deque([]) 

c.add(datetime.datetime.now()) 
time.sleep(0.75) 
c.add(datetime.datetime.now())  
assert(len(c) == 2) 
print(c) 
# deque([datetime.datetime(2010, 11, 19, 8, 50, 0, 91426), datetime.datetime(2010, 11, 19, 8, 50, 0, 842715)]) 

time.sleep(0.75) 
assert(len(c) == 1) 
print(c) 
# deque([datetime.datetime(2010, 11, 19, 8, 50, 0, 842715)]) 
+0

gracias! Me gusta el tiempo de espera enhebrado. ¿Mi ejemplo no era seguro para subprocesos? Los documentos dicen "deque es una implementación alternativa de colas ilimitadas con operaciones rápidas atómicas append() y popleft() que no requieren bloqueo". – hoju

+0

@Plumo: no soy un experto en juzgar la seguridad de los subprocesos, pero creo que su versión de ExpireCounter podría no ser segura para subprocesos. En el método 'add', la llamada a' datetime.now() 'puede no ser seguida inmediatamente por la llamada a' self.events.append'. Imagina múltiples hilos llamando al método 'add' casi simultáneamente. Muchas llamadas a 'datetime.now', pero los resultados se anexan a' self.events' en un orden desordenado. Si 'self.events' no está ordenado cronológicamente, entonces el ciclo while en el método' expire' puede terminar demasiado pronto. Por lo tanto, es posible que no se "copie" todos los elementos que se han agotado. – unutbu

1

Quizás desee un LRU caché. Aquí hay una que he tenido la intención de probar:

http://pypi.python.org/pypi/repoze.lru

Parece ser seguro para subprocesos.

+0

no no LRU. Quiero que caduque un valor después de exactamente el tiempo de espera dado, independientemente de la cantidad de valores que tenga y de si accedo a ellos. – hoju

+2

En ese caso, puede almacenar un tiempo de vencimiento con cada valor. ¿Qué tipo de semántica de contenedores quieres: list, set, dict u otra cosa? –

+0

no se refiere al tipo de contenedor, siempre que sea seguro para hilos – hoju

0

Esto es más o menos lo que quiero por ahora:

from datetime import datetime, timedelta 
from collections import deque 

class ExpireCounter: 
    """Tracks how many events were added in the preceding time period 
    """ 

    def __init__(self, timeout=timedelta(seconds=1)): 
     self.timeout = timeout 
     self.events = deque() 

    def add(self): 
     """Add event time 
     """ 
     self.events.append(datetime.now()) 

    def __len__(self): 
     """Return number of active events 
     """ 
     self.expire() 
     return len(self.events) 

    def expire(self): 
     """Remove any expired events 
     """ 
     now = datetime.now() 
     try: 
      while self.events[0] + self.timeout < now: 
       self.events.popleft() 
     except IndexError: 
      pass # no more events 


if __name__ == '__main__': 
    import time 
    c = ExpireCounter() 
    assert(len(c) == 0) 
    c.inc() 
    time.sleep(0.75) 
    c.inc() 
    assert(len(c) == 2) 
    time.sleep(0.75) 
    assert(len(c) == 1) 
Cuestiones relacionadas