Lock和RLock有什么区别


71

文档

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

我不确定为什么我们需要这个?Rlock和之间有什么区别Lock

Answers:


128

主要区别在于aLock只能获取一次。在发布之前,无法再次获取它。(发布后,任何线程都可以重新获取它)。

一个RLock在另一方面,可以由同一个线程来获取多次。它需要被释放相同的次数才能被“解锁”。

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


这是一个示例,说明为什么RLock有时有用。假设您有:

def f():
  g()
  h()

def g():
  h()
  do_something1()

def h():
  do_something2()

比方说,所有的fgh公共(即可以直接由外部调用程序调用),所有这些都需要同步化。

使用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()

2
那么,有没有使用任何实用的“好处” Lock
Mateen Ulhaq,

4
@MateenUlhaq,是的。Lock操作更快。
shx2

4
抱歉,如果这是一个愚蠢的问题,但是为什么我要多次获取一个锁,如果我需要增加一个计数器,我只是获取一个Lock()并释放它,为什么我们需要一个计数器来保持递增或递减
PirateApp '19

@PirateApp假设您获得了粒度锁定(即:在文件上)并执行了相当昂贵的操作(即:将其解密)。一个rlock可以防止死锁形成一系列复杂的依赖关系,这些依赖关系也可以尝试获取同一锁。
Erik Aronesty '19

@MateenUlhaq,我很抱歉。我已读过此评论“ @MateenUlhaq,是的。锁定操作更加快捷。– shx2 18年11月22日,18:11”,并且完全错过了shx2而不是您的经历。我的同事曾经使用过Lock(),但我已经找到了RLock(),并且看起来更好,更安全。所以我确实想知道同样的事情:为什么有人会使用Lock()?
Valentyn

11

为了扩展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
Future-Jim

没错,我更新了逻辑以非递归分支开始。
克里斯(Kris)

2

RLock称为递归锁。基本上,这是只有持有人才能释放的锁。在Lock中,任何线程都可以释放。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.