答案 0 :(得分:42)
这是我看到使用的一个例子:
时有用
您希望从类外部获取线程,并在类中使用相同的方法:
class X:
def __init__(self):
self.a = 1
self.b = 2
self.lock = threading.RLock()
def changeA(self):
with self.lock:
self.a = self.a + 1
def changeB(self):
with self.lock:
self.b = self.b + self.a
def changeAandB(self):
# you can use chanceA and changeB threadsave!
with self.lock:
self.changeA() # a usual lock would block in here
self.changeB()
更明显:
lock = threading.RLock()
def a(...):
with lock:
a(...) # somewhere inside
其他线程必须等到第一次调用a
完成=线程所有权。
<强>性能强>
通常我开始使用Lock进行编程,当出现情况1或2时,我切换到RLock。 Until Python 3.2由于附加代码,RLock应该慢一点。它使用Lock:
Lock = _allocate_lock # line 98 threading.py
def RLock(*args, **kwargs):
return _RLock(*args, **kwargs)
class _RLock(_Verbose):
def __init__(self, verbose=None):
_Verbose.__init__(self, verbose)
self.__block = _allocate_lock()
主题所有权
在给定的帖子中,您可以随意获取RLock
。其他线程需要等待,直到此线程再次释放资源。
这与Lock
不同,后者暗示'函数调用所有权'(我会这样称呼):另一个函数调用必须等到最后一个阻塞函数释放资源,即使它是在同一个线程中=即使它被另一个函数调用。
何时使用Lock代替RLock
当您拨打无法控制的资源外部时。
下面的代码有两个变量:a和b,RLock用于确保a == b * 2
import threading
a = 0
b = 0
lock = threading.RLock()
def changeAandB():
# this function works with an RLock and Lock
with lock:
global a, b
a += 1
b += 2
return a, b
def changeAandB2(callback):
# this function can return wrong results with RLock and can block with Lock
with lock:
global a, b
a += 1
callback() # this callback gets a wrong value when calling changeAandB2
b += 2
return a, b
在changeAandB2
中,Lock会是正确的选择,尽管它会阻止。或者可以使用RLock._is_owned()
使用错误来增强它。实现Observer模式或Publisher-Subscriber并在之后添加锁定时,可能会出现changeAandB2
等函数。
答案 1 :(得分:3)
原语锁(Lock)是一个同步原语,在锁定时不属于特定线程。
对于可重复锁定(RLock)在锁定状态下,某些线程拥有锁定;在解锁状态下,没有线程拥有它。 如果此线程已拥有锁,则调用此命令时,将递归级别递增1,并立即返回。如果线程没有锁定它等待所有者释放锁定。 释放锁定,递减递归级别。如果在减量之后它为零,则将锁重置为未锁定。
我不认为存在一些性能差异而非概念性差异。
答案 2 :(得分:3)
这是RLock的另一个用例。假设您有一个支持并发访问的面向Web的用户界面,但您需要管理对外部资源的某些类型的访问。例如,您必须保持内存中的对象与数据库中的对象之间的一致性,并且您有一个控制对数据库的访问的管理器类,您必须确保以特定顺序调用这些方法,而不是同时调用。
你可以做的是创建一个RLock和一个监护人线程,通过不断获取它来控制对RLock的访问,并仅在发信号时释放。然后,确保控制访问所需的所有方法都在运行之前获取锁定。像这样:
def guardian_func():
while True:
WebFacingInterface.guardian_allow_access.clear()
ResourceManager.resource_lock.acquire()
WebFacingInterface.guardian_allow_access.wait()
ResourceManager.resource_lock.release()
class WebFacingInterface(object):
guardian_allow_access = Event()
resource_guardian = Thread(None, guardian_func, 'Guardian', [])
resource_manager = ResourceManager()
@classmethod
def resource_modifying_method(cls):
cls.guardian_allow_access.set()
cls.resource_manager.resource_lock.acquire()
cls.resource_manager.update_this()
cls.resource_manager.update_that()
cls.resource_manager.resource_lock.release()
class ResourceManager(object):
resource_lock = RLock()
def update_this(self):
if self.resource_lock.acquire(False):
try:
pass # do something
return True
finally:
self.resource_lock.release()
else:
return False
def update_that(self):
if self.resource_lock.acquire(False):
try:
pass # do something else
return True
finally:
self.resource_lock.release()
else:
return False
通过这种方式,您可以确保以下事项: