python: 优雅地处理变量锁的方式?
我有一段代码,看起来像这样:
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
为什么要自动释放它。