Python 3.10中RLock无工作负载时多线程可获取锁的异常问询
Python 3.10中RLock的行为疑问:无负载时看似允许多线程获取锁?
在Python 3.10环境下,RLock(可重入锁)是线程感知锁,同一时间仅允许一个线程持有锁。但测试发现:3个线程无工作负载时,多个线程似乎能依次获取同一RLock,不符合预期;添加time.sleep模拟工作负载后,RLock正常生效,仅一个线程能获取锁并阻塞其他线程。这是Bug还是操作有误?
异常行为代码及输出
import threading lock = threading.RLock() def th(name): print(f"{name} tread started") lock.acquire() print(f"{name} tread end") th1 = threading.Thread(target=th, args=[1]) th2 = threading.Thread(target=th, args=[2]) th3 = threading.Thread(target=th, args=[3]) th1.start() th2.start() th3.start()
输出:
1 tread started 1 tread end 2 tread started 2 tread end 3 tread started 3 tread end
预期行为代码及输出
import threading import time lock = threading.RLock() def th(name): print(f"{name} tread started") lock.acquire() time.sleep(0.1) # 模拟工作负载 print(f"{name} tread end") th1 = threading.Thread(target=th, args=[1]) th2 = threading.Thread(target=th, args=[2]) th3 = threading.Thread(target=th, args=[3]) th1.start() th2.start() th3.start()
输出:
1 tread started 2 tread started 3 tread started 1 tread end
问题解析
这既不是Bug,也不是操作有误,而是线程调度与锁自动释放的机制导致的:
- 锁的显式释放缺失:两个示例的代码都没有在
lock.acquire()后调用lock.release(),但Python线程在退出时,会自动释放该线程持有的所有锁资源。 - 无负载时的线程调度:第一个示例中,线程执行速度极快,线程1在获取锁后,几乎瞬间就完成了后续代码并退出,锁被自动释放。此时线程2才被调度执行,自然能顺利获取锁,重复此过程就出现了依次执行的现象。
- 有负载时的阻塞效果:第二个示例中,
time.sleep(0.1)让线程1持有锁的时间大幅延长。在这段时间内,线程2、3被调度执行,尝试获取锁时会被RLock阻塞,直到线程1执行完sleep并退出、锁被释放后,其他线程才能继续。
正确的锁使用方式
为了避免这种依赖线程退出的隐式锁释放,应该始终显式释放锁,推荐使用with上下文管理器,它会自动处理锁的获取与释放,即使发生异常也能保证锁被正确释放:
import threading lock = threading.RLock() def th(name): print(f"{name} tread started") with lock: # 这里执行需要加锁的逻辑 print(f"{name} is holding the lock") print(f"{name} tread end") # 线程创建与启动逻辑不变
内容的提问来源于stack exchange,提问作者Pall Arpad
相关产品推荐
相关产品推荐

