提问者:小点点

Lock和RLock的区别是什么


从文件中:

线程。RLock()——一个返回新可重入锁对象的工厂函数。可重入锁必须由获取它的线程释放。一旦线程获取了可重入锁,同一线程可以再次获取它而不会阻塞;线程每次获取它时必须释放一次。

我不确定为什么我们需要这个?RlockLock有什么区别?


共3个答案

匿名用户

主要区别是Lock只能被获取一次。在它被释放之前,它不能被再次获取。(在它被释放后,它可以被任何线程重新获取)。

另一方面,RLock可以通过同一线程多次获取。需要释放相同次数才能“解锁”。

另一个区别是,获取的可以由任何线程释放,而获取的RLock只能由获取它的线程释放。

下面是一个例子,说明为什么RLock有时很有用。假设您有:

def f():
  g()
  h()

def g():
  h()
  do_something1()

def h():
  do_something2()

假设所有的fgh都是公共的(即可以由外部调用方直接调用),并且所有这些都需要同步。

使用,可以执行以下操作:

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中,任何线程都可以释放。