Python条件“有”锁设计

时间:2011-03-03 19:34:23

标签: python locking with-statement

我正在尝试使用with语句进行一些共享锁定

def someMethod(self, hasLock = False):
     with self.my_lock:
         self.somethingElse(hasLock=True)


def somethingElse(self, hasLock = False):
    #I want this to be conditional...
    with self.my_lock:
          print 'i hate hello worlds"

那有道理吗?如果我还没有锁,我基本上只想做这个。

除了能够实现这一点,它是一个糟糕的设计?我应该自己获得/释放吗?

5 个答案:

答案 0 :(得分:37)

只需使用可重入的threading.RLock,即可以通过同一个帖子多次获取。

http://docs.python.org/library/threading.html#rlock-objects

为清楚起见,RLock语句中使用了with,就像示例代码中一样:

lock = threading.RLock()

def func1():
    with lock:
        func2()

def func2():
    with lock: # this does not block even though the lock is acquired already
        print 'hello world'

至于这是否是糟糕的设计,我们需要更多的背景。为什么两个函数都需要获取锁?何时func2func1以外的其他人调用?

答案 1 :(得分:5)

Python orshort circuiting,因此您可以使锁定成为条件:

def somethingElse(self, hasLock = False):
    #I want this to be conditional...
    with hasLock or self.my_lock:
          print 'i hate hello worlds'

不幸的是,它并不那么容易,因为布尔值不是来自with语句的有效返回。您需要创建一个包含__enter____exit__的类来包装布尔True值。

这是我尚未测试过的一种可能的实现方式。

from contextlib import contextmanager

@contextmanager
def withTrue():
    yield True

def withbool(condition):
    if condition:
        return withTrue()
    return False

def somethingElse(self, hasLock = False):
    with withbool(hasLock) or self.my_lock():
          print 'i hate hello worlds'

这是一个很简单的样板,所以RLock解决方案看起来像一个胜利者。但是,此解决方案可能在不同的上下文中有用。

答案 2 :(得分:1)

为什么不:

def someMethod(self):
     with self.my_lock:
         self.somethingNoLock()

def somethingElse(self):
    with self.my_lock:
         self.somethingNoLock()

def somethingNoLock(self):
    print 'i hate hello worlds"

请注意,虽然我的解决方案中someMethodsomethingElse相同,但一般来说它们会有所不同。您可以在somethingNoLock周围放置另一个包装器,以便锁定获取和释放不会重复多次。

这简单明了。只是因为可以使用重入锁定锤,我不建议在有更简单,不易碎的方法时使用它。

对rlock的更具体的批评是,创建可重入锁的行远离以可重入方式获取锁的代码。如果有人说重入锁与另一个不可重入的锁或者更改创建锁的行,那么这有点脆弱。

答案 3 :(得分:0)

使用with语句优于acquire()release()函数。这样,如果发生错误,锁将被释放。

答案 4 :(得分:0)

with语句是实现锁定的好方法,因为锁定是一种完美的资源获取模式。虽然,你当前的例子不起作用,但你需要在somethingElse()中围绕with语句使用if语句。