【发布时间】:2014-05-18 02:57:40
【问题描述】:
来自docs:
threading.RLock() -- 返回一个新的可重入锁对象的工厂函数。重入锁必须由获取它的线程释放。一旦一个线程获得了可重入锁,同一个线程可以再次获得它而不会阻塞;线程每次获得它时都必须释放它一次。
我不确定我们为什么需要这个?
Rlock 和 Lock 有什么区别?
【问题讨论】:
标签: python multithreading locking reentrancy
来自docs:
threading.RLock() -- 返回一个新的可重入锁对象的工厂函数。重入锁必须由获取它的线程释放。一旦一个线程获得了可重入锁,同一个线程可以再次获得它而不会阻塞;线程每次获得它时都必须释放它一次。
我不确定我们为什么需要这个?
Rlock 和 Lock 有什么区别?
【问题讨论】:
标签: python multithreading locking reentrancy
主要区别在于Lock 只能获取一次。它不能再次获得,直到它被释放。 (发布后,任何线程都可以重新获取)。
另一方面,RLock 可以被同一个线程多次获取。它需要释放相同的次数才能“解锁”。
另外一个区别是,获取的Lock可以被任何线程释放,而获取的RLock只能被获取它的线程释放。
这是一个示例,说明为什么 RLock 有时很有用。假设你有:
def f():
g()
h()
def g():
h()
do_something1()
def h():
do_something2()
假设所有f、g 和h 都是public(即可以由外部调用者直接调用),并且它们都需要同步。
使用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 有什么实际的“好处”吗?
Lock 操作更快。
为了扩展 shx2 的 answer,为什么要使用一个与另一个的原因可能如下:
普通的Lock(互斥体)通常更快、更安全。
使用RLock 的原因是为了避免死锁,例如递归。例如,让我们在递归factorial 函数中加一个锁。 (诚然有些做作)
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,递归调用可以根据需要多次重新进入同一个锁。因此名称为 reentrant(或 recursive)锁。
【讨论】:
if n ==1: return 1
RLock 称为递归锁。基本上它是一个只有持有者才能释放的锁。在Lock中,任何线程都可以释放。
【讨论】: