Python:优雅地处理变量锁的方式?

7

我有一些代码看起来像这样:

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

虽然这样做看起来有点丑陋,但是需要进行大量的获取和释放。以下方式更为美观:

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

但是这样会比严格必要的时间更长地保持锁定,尤其是如果 self.logger.error 需要一段时间(例如写入磁盘),那么情况就更加如此了。有没有折衷方案可以尽可能地减少锁定时间,同时又能让代码更加优雅?

3个回答

6
也许您需要将此逻辑分开处理,例如:
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

此外,您需要告诉您的searchingLock自动释放的原因。


4
如何将变量和锁(variable & lock)封装在一个类中:
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)

并且使用如下:

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

评论:

有时我会使用带有自定义删除器的boost::shared_ptr来实现同样的目的,即返回一个在超出范围时被释放的未锁定变量。


1

这将为您节省一个 "self.searchingLock.release()"。虽然它可能不是很符合 Python 的风格,但它确实能够完成工作。

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

你甚至可以轻松地将前4行代码拆分成另一个函数。 - Dan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接