2010-11-18 6 views
5

Sono in un contenitore Python sicuro da file in cui i valori vengono automaticamente rimossi dopo un certo tempo. Esiste una classe del genere?contenitore in cui i valori scadono in python

+3

possibile duplicato: http://stackoverflow.com/questions/3927166/automatically-expiring-variable – mouad

+0

I am after a thread s classe sicura con timeout per ogni valore. Questo esempio utilizza un elenco e un timeout globale. – hoju

risposta

5

Ecco una versione thread-safe di 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) 

che può essere utilizzato in questo modo:

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

grazie! Mi piace il timeout del thread. Il mio esempio non è sicuro? I documenti dicono "deque è un'implementazione alternativa di code illimitate con operazioni atomic append() e popleft() che non richiedono il locking." – hoju

+0

@Plumo: Non sono esperto nel giudicare la sicurezza dei thread, ma penso che la tua versione di ExpireCounter potrebbe non essere thread-safe. Nel metodo 'add', la chiamata a' datetime.now() 'potrebbe non essere seguita immediatamente dalla chiamata a' self.events.append'. Immagina più thread che chiamano il metodo 'add' quasi simultaneamente. Un sacco di chiamate a 'datetime.now', ma i risultati vengono aggiunti a' self.events' in un ordine confuso. Se 'self.events' non è ordinato cronologicamente, allora il ciclo while nel metodo' expire' potrebbe finire troppo presto. Pertanto, potrebbe non riuscire a "popleft" tutti gli elementi che sono scaduti. – unutbu

1

Forse si desidera una cache LRU. Ecco quello che ho in mente di provare:

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

Sembra essere thread-safe.

+0

no not LRU. Voglio che un valore scada dopo esattamente il timeout specificato, indipendentemente da quanti valori ho e se li accedo. – hoju

+2

In tal caso, è possibile memorizzare una data di scadenza con ciascun valore. Che tipo di semantica del contenitore vuoi: lista, set, dict o qualcos'altro? –

+0

non riguarda il tipo di contenitore purché thread safe – hoju

0

Questo è più o meno quello che voglio per ora:

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) 
Problemi correlati