You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,也不是操作有误,而是线程调度与锁自动释放的机制导致的:

  1. 锁的显式释放缺失:两个示例的代码都没有在lock.acquire()后调用lock.release(),但Python线程在退出时,会自动释放该线程持有的所有锁资源。
  2. 无负载时的线程调度:第一个示例中,线程执行速度极快,线程1在获取锁后,几乎瞬间就完成了后续代码并退出,锁被自动释放。此时线程2才被调度执行,自然能顺利获取锁,重复此过程就出现了依次执行的现象。
  3. 有负载时的阻塞效果:第二个示例中,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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 13:39:40