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

时间:2010-08-11 20:34:17

标签: python multithreading locking thread-safety

我的代码看起来像这样:

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 个答案:

答案 0 :(得分: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自动释放它的原因。

答案 1 :(得分:2)

如何包装变量&锁定课程:

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与自定义删除器一起使用来实现相同的功能,即返回一个在超出范围时释放的未锁定变量。

答案 2 :(得分:1)

这会为你节省一个“self.searchingLock.release()”。猜猜它不是非常pythonic或任何东西,但它做的工作

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