2010-08-11 2 views
7

Ich habe Code, der wie so etwas wie folgt aussieht:Python: elegante Möglichkeit, mit Sperre für eine Variable umzugehen?

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 

es ist irgendwie hässlich, though. viele Erwerbungen und Freisetzungen. das sieht schöner:

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 

aber das hält die Sperre länger als unbedingt nötig, espcially wenn self.logger.error eine Weile dauert, (wie wenn er schreibt auf der Festplatte, die es tut). Gibt es irgendeinen Mittelweg zwischen dem Halten des Schlosses so wenig wie möglich, aber schönerem Code?

Antwort

6

Vielleicht müssen Sie wie diese Logik trennen:

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 

Und Additionaly Sie sagen Sie Ihrem searchingLock den Grund, es automatisch zu veröffentlichen.

1

Dies wird Ihnen ein retten „self.searchingLock.release()“ Ich denke, es ist nicht sehr pythonic oder etwas ist, aber es macht den Job

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 =) ich mag es – Claudiu

+0

Sie könnten sogar die ersten 4 Zeilen in eine andere Funktion leicht brechen. – user37078

2

Wie über die Variable & Sperre in einer Klasse Verpackung:

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) 

Und da dies:

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

Kommentar:

ich manchmal boost :: shared_ptr mit ein benutzerdefinierter Deleter, um dasselbe zu erreichen, dh eine unverriegelte Variable zurückgeben, die freigegeben wird, wenn sie nicht mehr s ist bewältigen.