从文档:
threading.RLock()-一个工厂函数,返回一个新的可重入锁对象。可重入锁必须由获取它的线程释放。一旦线程获取了可重入锁,同一线程就可以再次获取它而不会阻塞;线程必须在每次获取它后释放一次。
我不确定为什么我们需要这个?Rlock
和之间有什么区别Lock
?
Answers:
主要区别在于aLock
只能获取一次。在发布之前,无法再次获取它。(发布后,任何线程都可以重新获取它)。
一个RLock
在另一方面,可以由同一个线程来获取多次。它需要被释放相同的次数才能被“解锁”。
另一个区别是,获取对象Lock
可以由任何线程释放,而获取对象RLock
只能由获取它的线程释放。
这是一个示例,说明为什么RLock
有时有用。假设您有:
def f():
g()
h()
def g():
h()
do_something1()
def h():
do_something2()
比方说,所有的f
,g
和h
有公共(即可以直接由外部调用程序调用),所有这些都需要同步化。
使用Lock
,您可以执行以下操作:
lock = Lock()
def f():
with lock:
_g()
_h()
def g():
with lock:
_g()
def _g():
_h()
do_something1()
def h():
with lock:
_h()
def _h():
do_something2()
基本上,因为f
不能调用g
获取锁后,它需要调用的“原始”版本g
(即_g
)。因此,您最终获得了每个功能的“同步”版本和“原始”版本。
使用一个RLock
优雅解决了这个问题:
lock = RLock()
def f():
with lock:
g()
h()
def g():
with lock:
h()
do_something1()
def h():
with lock:
do_something2()
Lock
操作更快。
为了扩展shx2的答案,您为什么要使用一个与另一个相比可能是以下原因:
常规Lock
(互斥)通常更快,更安全。
使用的原因RLock
是避免由于例如递归导致的死锁。例如,让我们在递归阶乘函数中加一个锁。(当然有些人为的)
from threading import Lock
lock = Lock()
def factorial(n):
assert n > 0
if n == 1:
return 1
with lock:
out = n * factorial(n - 1)
return out
该函数将由于递归调用而导致死锁。RLock
但是,如果改为使用,则递归调用可以根据需要多次重新输入相同的锁。因此,名称可重入(或递归)锁。
if n ==1: return 1
RLock称为递归锁。基本上,这是只有持有人才能释放的锁。在Lock中,任何线程都可以释放。
Lock
?