开发者

python: elegant way to deal with lock on a variable?

开发者 https://www.devze.com 2023-01-11 08:30 出处:网络
I have code that looks like something like this: def startSearching(self): self.searchingLock.acquire()

I have code that looks like something like this:

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

it's kind of ugly, though. lots of acquires and releases. this looks prettier:

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

        self.searching = True

    #some more init code,开发者_C百科 then start the thread which
    #constantly checks self.searching to determine when to stop

but this keeps the lock longer than strictly necessary, espcially if self.logger.error takes a while (like if it writes to disk, which it does). is there any middle ground between holding the lock as little as possible but having prettier code?


Maybe you need to separate this logic like:

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

And additionaly you telling your searchingLock the reason to release it automaticaly.


How about wrapping the variable & lock in a class:

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)

And use as this:

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

Comment:

I sometimes use boost::shared_ptr with a custom deleter to achieve the same thing, i.e. return an unlocked variable that's released when it goes out of scope.


This will save you one "self.searchingLock.release()" Guess it's not very pythonic or anything but it does the 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

精彩评论

暂无评论...
验证码 换一张
取 消