2010-11-18 15 views
5

Jestem po wątku bezpieczne kontener Python, w którym wartości są automatycznie usuwane po pewnym czasie. Czy taka klasa istnieje?Kontener, w którym wartości wygasają w pythonie

+3

możliwy duplikat: http://stackoverflow.com/questions/3927166/automatically-expiring-variable – mouad

+0

Jestem po wątku s klasa afe z limitami czasu dla każdej wartości. W tym przykładzie użyto listy i globalnego limitu czasu. – hoju

Odpowiedz

5

Tutaj jest wątek bezpieczne wersja 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) 

które mogą być używane tak:

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

dzięki! Lubię gwintowany limit czasu. Czy mój przykład nie był bezpieczny dla wątków? Dokumenty mówią, że "deque" to alternatywna implementacja nieskoordynowanych kolejek z szybkimi operacjami atomowej append() i popleft(), które nie wymagają blokowania. " – hoju

+0

@ Plumo: Nie jestem ekspertem w ocenie bezpieczeństwa wątków, ale myślę, że Twoja wersja ExpireCounter może nie być bezpieczna dla wątków. W metodzie 'add' nie można natychmiast wywołać' datetime.now() 'wywołaniem' self.events.append'. Wyobraź sobie, że wiele wątków wywołuje metodę 'add' w pobliżu jednocześnie. Partie wywołań do 'datetime.now', ale wyniki zostają dołączone do' self.events' w pomieszanej kolejności. Jeśli 'self.events' nie jest uporządkowany chronologicznie, to pętla while w metodzie' expire' może zakończyć się zbyt wcześnie. W ten sposób może przestać 'popleft' wszystkie elementy, które przekroczyły limit czasu. – unutbu

1

Być może potrzebujesz pamięci podręcznej LRU. Oto jeden Byłem sens wypróbować:

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

To wydaje się być bezpieczne dla wątków.

+0

no not LRU. Chcę, aby wartość wygasała po dokładnie określonym czasie, niezależnie od tego, ile mam wartości i czy uzyskuję do nich dostęp. – hoju

+2

W takim przypadku można zapisać czas wygaśnięcia dla każdej wartości. Jaki rodzaj semantyki kontenera chcesz: list, zestaw, dykt, czy coś innego? –

+0

nie dotyczy rodzaju kontenera, o ile jest bezpieczny dla nitek – hoju

0

To jest mniej więcej to, co chcę teraz:

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) 
Powiązane problemy