2010-08-11 10 views
7

que tienen código que se parece a algo como esto:python: ¿una forma elegante de lidiar con el bloqueo de una variable?

def startSearching(self): 
    self.searchingLock.acquire() 
    searching = self.searching 
    if self.searching: 
     self.searchingLock.release() 
     self.logger.error("Already searching!") 
     return False 

    self.searching = True 
    self.searchingLock.release() 

    #some more init code, then start the thread which 
    #constantly checks self.searching to determine when to stop 

que es un poco feo, sin embargo. muchas adquisiciones y lanzamientos. esto se ve más bonita:

def startSearching(self): 
    with self.searchingLock: 
     if self.searching: 
      self.logger.error("Already searching!") 
      return False 

     self.searching = True 

    #some more init code, then start the thread which 
    #constantly checks self.searching to determine when to stop 

pero esto mantiene el bloqueo más largo de lo estrictamente necesario, especiamente si self.logger.error toma un tiempo (como si se escribe en el disco, lo que lo hace). ¿Hay algún punto medio entre mantener el bloqueo lo menos posible pero tener un código más bonito?

Respuesta

6

Tal vez usted necesita para separar esta lógica como:

def initSearch(self): 
    with self.searchingLock: 
     if self.searching : raise SearchingError('AlreadySearching') 
     self.searching = True 
def startSearching(self): 
    try: self.initSearch() 
    except SearchingError as error : 
     self.logger.error(error.message) 
     return False 
    #some more init code, then start the thread which 
    #constantly checks self.searching to determine when to stop 

Y adicionalmente se diciéndole a su searchingLock la razón para liberarlo automáticamente.

1

Esto le ahorrará una "self.searchingLock.release()" supongo que no es muy Pythonic ni nada, pero hace el trabajo

def startSearching(self): 
    self.searchingLock.acquire() 
    already_searching = self.searching 
    self.searching = True # Since it'll be true in both scenarios 
    self.searchingLock.release() 

    if already_searching: 
     self.logger.error("Already searching!") 

    return not already_searching 
+0

heh clever =) me gusta – Claudiu

+0

Incluso podría romper fácilmente las primeras 4 líneas en otra función. – user37078

2

¿Qué hay de envolver la variable de cerradura & en una clase:

class LockedVariable(object): 
    def __init__(self, value, lock=None): 
     self._value = value 
     self._lock = lock if lock else threading.RLock() 
     self._locked = false: 

    @property 
    def locked(self): 
     return self._locked 

    def assign(self, value): 
     with self: 
      self._value = value 

    def release(): 
     self._locked = False 
     return self._lock.release() 

    def __enter__(self): 
     self._lock.__enter__() 
     self._locked = True 
     return self._value 

    def __exit__(self, *args, **kwargs): 
     if self._locked: 
      self._locked = False 
      return self._lock.__exit__(*args, **kwargs) 

y el uso como esto:

locked_dict = LockedVariable({}) 

with locked_dict as value: 
    value['answer'] = 42 

    if locked_dict.locked: 
     locked_dict.release() 
     print 'eureka! :)' 
     return  

if locked_dict.locked: 
    print 'bahh! :('   

Comentario:

a veces uso impulso :: shared_ptr con un eliminador personalizado para lograr lo mismo, es decir, devolver una variable desbloqueada que se libera cuando sale de s capa pluvial.

Cuestiones relacionadas