来自 文档:
threading.RLock() -- 一个工厂函数,返回一个新的可重入锁对象。可重入锁必须由获取它的线程释放。一旦一个线程获取了可重入锁,同一个线程可以再次获取它而不会阻塞;但是线程每次获取锁后必须释放相同次数的锁。
我不确定我们为什么需要这个?
Rlock
和 Lock
有什么区别?
来自 文档:
threading.RLock() -- 一个工厂函数,返回一个新的可重入锁对象。可重入锁必须由获取它的线程释放。一旦一个线程获取了可重入锁,同一个线程可以再次获取它而不会阻塞;但是线程每次获取锁后必须释放相同次数的锁。
我不确定我们为什么需要这个?
Rlock
和 Lock
有什么区别?
主要区别在于Lock
只能被获取一次,必须释放后才能重新获取(任何线程都可重新获取)。
而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()
为了进一步解释shx2的回答,使用Lock
和RLock
的原因可能是以下两个方面:
普通的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中,任何线程都可以释放。
Lock
操作更快。 - shx2