2010-08-11 9 views
7

Ho codice che assomiglia a qualcosa di simile:python: un modo elegante per gestire il lock su una variabile?

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 

è una specie di brutto, però. un sacco di acquisti e rilasci. questo sembra più bella:

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 

ma questo mantiene il blocco più a lungo di quanto strettamente necessario, se espcially self.logger.error prende un po '(come se si scrive su disco, cosa che fa). c'è una via di mezzo tra tenere la serratura il meno possibile ma avere un codice più bello?

risposta

6

Forse è necessario separare questa logica come:

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 

E additionaly voi dicendo al tuo searchingLock il motivo per rilasciarlo automaticamente.

1

Questo vi farà risparmiare un "self.searchingLock.release()" Indovina non è molto divinatorio o qualcosa, ma non il lavoro

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 intelligente =) Mi piace – Claudiu

+0

Si potrebbe anche facilmente interrompere le prime 4 linee in un'altra funzione. – user37078

2

Come su avvolgendo il & blocco variabile in una classe:

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) 

e utilizzare come questo:

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! :('   

Commento:

volte uso boost :: shared_ptr con un deleter personalizzato per ottenere la stessa cosa, ovvero restituire una variabile sbloccata che viene rilasciata quando esce da s far fronte.

Problemi correlati