【问题标题】:What is the difference between Lock and RLockLock和RLock有什么区别
【发布时间】:2014-05-18 02:57:40
【问题描述】:

来自docs

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

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

【问题讨论】:

    标签: python multithreading locking reentrancy


    【解决方案1】:

    主要区别在于Lock 只能获取一次。它不能再次获得,直到它被释放。 (发布后,任何线程都可以重新获取)。

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

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


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

    def f():
      g()
      h()
    
    def g():
      h()
      do_something1()
    
    def h():
      do_something2()
    

    假设所有fgh 都是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 有什么实际的“好处”吗?
    • @MateenUlhaq,是的。 Lock 操作更快。
    • 对不起,如果这是一个愚蠢的问题,但为什么我要多次获取锁,如果我需要增加一个计数器,我只需获取一个 Lock() 并释放它,为什么我们需要一个计数器保持递增或递减
    • @PirateApp 假设您获得了粒度锁(即:在文件上)并做一些相当昂贵的事情(即:解密它)。 rlock 可以防止在一系列复杂的依赖关系中形成死锁,这些依赖关系也可能会尝试获取相同的锁。
    • @MateenUlhaq 我很抱歉。我已阅读此评论“@MateenUlhaq,是的。锁定操作更快。- shx2 18 年 11 月 22 日 18:11”并且完全错过了它是由 shx2 而不是你。我的同事曾经使用 Lock(),但我发现 RLock() 看起来更好更安全。所以我确实想知道:为什么有人会使用 Lock()?
    【解决方案2】:

    为了扩展 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
    • 你说得对,我更新了逻辑以从非递归分支开始。
    【解决方案3】:

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

    【讨论】:

    • en.wikipedia.org/wiki/Reentrant_mutex -> 在计算机科学中,可重入互斥锁(recursive mutex,递归锁)是一种特殊类型的互斥(mutex)设备,可以被同一个进程/线程多次锁定,而不会导致死锁。
    猜你喜欢
    • 1970-01-01
    • 2016-10-07
    • 2017-12-07
    • 1970-01-01
    • 1970-01-01
    • 2016-08-16
    • 2013-06-07
    • 1970-01-01
    • 2012-07-11
    相关资源
    最近更新 更多