问题 RLock是否比Lock更合理?


Python中的线程模块提供了两种锁:公共锁和可重入锁。在我看来,如果我需要锁,我应该总是喜欢RLock而不是Lock;主要是为了防止死锁情况。

除此之外,我看到两点,何时更喜欢Lock over RLock:

  • RLock具有更复杂的内部结构,因此可能具有更差的性能。
  • 由于某种原因,我想阻止线程通过锁递归。

我的推理是否正确?你能指出其他方面吗?


2059
2017-11-30 21:32


起源

#2不太可能是一个好理由;它不是保证死锁的唯一情况是递归获得非阻塞并且当它无法验证它是否持有锁时有一些合理的操作过程。并且#1不适用于Python 3.2+。一个合理的理由 Lock 是否必须在与获取锁的线程不同的线程中释放锁。 - ShadowRanger


答案:


两点:

  • 在官方发布的Python版本(2.4,2.5 ......最多3.1)中,RLock比Lock慢得多,因为Locks在Python中用C和RLocks实现(这将在3.2中改变)
  • 一个锁可以从任何线程释放(不一定是获取()它的线程),而RLock必须由获取它的同一个线程释放

最重要的是,我建议只使用RLock,如果它匹配你正在寻找的语义,否则默认情况下坚持使用Locks。


10
2017-12-29 23:21



那说, RLocks可以简化代码。如果有两个方法都需要保持锁定,而另一个方法则调用另一个方法,那么构造为plain Lock 要求您将“内部”方法拆分为未锁定的实用程序,公共名称锁定并调用内部方法,而“外部”方法直接调用解锁的实用程序。每次您参与此表单的代码重用时,您都需要这样做。此外, RLock 消除了在一个线程中静默锁定并在另一个线程中解锁的风险(它从同一个线程强制执行锁定和解锁);在常见情况下防止错误。 - ShadowRanger
鉴于3.1及以下的性能,我可以看到一般推荐 Lock 出于实际原因,但在3.2+中, RLock 使用起来不那么复杂,可以防止常见错误,同样有效;你真的用 Lock 只有在你需要的时候 Lock 特定功能(例如,跨线程获取/释放,使用它作为服务员的障碍;服务员创建 Lock, acquires一次,添加到等待锁列表, acquire阻止;警报然后 releases让... waiter 继续(当然,我只是在描述什么 Condition 为你做,所以不要自己这样做)。 - ShadowRanger


通常,您应该构造代码,使得您永远不需要递归锁定正常操作(基本上它会强制您在他们正在保护的受保护数据结构周围紧紧使用锁)。因此,您希望捕获异常的递归锁定。


3
2017-11-30 22:39



你的回答意味着 这个例子 用来激励 RLock 首先应使用更严格的锁重写,此时它不需要 RLock。你同意吗?如果是这样,什么是激发需求的好例子 RLock? - max