2010-08-11 3 views
7

J'ai le code qui ressemble à quelque chose comme ceci:python: une façon élégante de gérer le verrouillage d'une 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 

c'est un peu laid, cependant. beaucoup d'acquisitions et de communiqués. cela ressemble plus jolie:

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 

mais cela maintient le blocage plus que le strict nécessaire, espcially si self.logger.error prend un certain temps (comme si elle écrit sur le disque, ce qu'il fait). Y a-t-il un juste milieu entre le maintien de la serrure aussi peu que possible, mais ayant un code plus joli?

Répondre

6

Peut-être que vous avez besoin de séparer cette logique comme:

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 

Et additionaly vous en disant à votre searchingLock la raison de le libérer automatiquement.

1

Cela vous fera économiser un « self.searchingLock.release() » Je suppose que ce n'est pas très pythonique ou quoi que ce soit, mais il fait le travail

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 =) j'aime ça – Claudiu

+0

Vous pourriez même facilement casser les 4 premières lignes dans une autre fonction. – user37078

2

Que diriez-vous envelopper la variable verrouillage & dans une 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) 

Et utiliser comme ceci:

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

Commentaire:

J'utilise parfois boost :: shared_ptr avec un suppresseur personnalisé pour atteindre la même chose, à savoir retourner une variable déverrouillée qui est libérée quand il s chape.

Questions connexes