从文件中:
线程。RLock()——一个返回新可重入锁对象的工厂函数。可重入锁必须由获取它的线程释放。一旦线程获取了可重入锁,同一线程可以再次获取它而不会阻塞;线程每次获取它时必须释放一次。
我不确定为什么我们需要这个?Rlock
和Lock
有什么区别?
主要区别是Lock
只能被获取一次。在它被释放之前,它不能被再次获取。(在它被释放后,它可以被任何线程重新获取)。
另一方面,RLock
可以通过同一线程多次获取。需要释放相同次数才能“解锁”。
另一个区别是,获取的锁
可以由任何线程释放,而获取的RLock
只能由获取它的线程释放。
下面是一个例子,说明为什么RLock
有时很有用。假设您有:
def f():
g()
h()
def g():
h()
do_something1()
def h():
do_something2()
假设所有的f
、g
和h
都是公共的(即可以由外部调用方直接调用),并且所有这些都需要同步。
使用锁
,可以执行以下操作:
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
的“原始”版本(即\u g
)。因此,每个函数最终都有一个“同步”版本和一个“原始”版本。
使用RLock
优雅地解决了这个问题:
lock = RLock()
def f():
with lock:
g()
h()
def g():
with lock:
h()
do_something1()
def h():
with lock:
do_something2()
为了扩展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
,递归调用可以根据需要多次重新输入同一个锁。因此被称为可重入(或递归)锁。
RLock被称为递归锁。基本上它是一个只有持有者才能释放的锁。在Lock中,任何线程都可以释放。