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

7 投票
3 回答
4105 浏览
提问于 2025-04-16 02:39

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

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 个回答

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

可以把这个变量和锁放在一个类里,这样做怎么样:

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配合一个自定义的删除器,来实现同样的效果,也就是返回一个解锁的变量,当它超出作用域时会被释放。

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 为什么要自动释放它。

撰写回答