多线程共用 Progress 实例会崩溃,因 Console 非线程安全且 Progress 共享状态未加锁;应使用 thread-safe Console + 独立 task_id 隔离更新,并统一所有输出到该 Console。

rich.progress 多线程直接共用 Progress 实例会崩溃
直接在多个线程里调用同一个 Progress 对象的 update() 或 advance(),大概率触发 RuntimeError: Working outside of application context(尤其搭配 Console 的非主线程刷新)或更隐蔽的显示错乱、卡死。根本原因是 rich.console.Console 默认不是线程安全的,且 Progress 内部共享状态(如任务列表、渲染计时器)未加锁。
推荐方案:用 thread-safe Console + task_id 隔离更新
核心是让所有线程共用一个线程安全的 Console 实例,并通过 add_task() 为每个线程分配独立 task_id,再用该 ID 更新——避免状态竞争。关键点:
-
Console必须显式传入force_terminal=True, color_system="truecolor"等参数,并设置soft_wrap=True(减少渲染冲突) - 主线程创建
Progress时,传入这个共享Console;各线程只调用update(task_id, advance=1),绝不调用add_task()或修改任务元数据 - 所有线程必须等
Progress启动后(即进入with progress:块)才能开始更新,否则task_id无效
示例:
from rich.progress import Progress from rich.console import Console from threading import Thread import timeconsole = Console(force_terminal=True, soft_wrap=True) progress = Progress(console=console)
def worker(taskid, n): for in range(n): time.sleep(0.1) progress.update(task_id, advance=1) # 安全:只更新自己 task
with progress: task1 = progress.add_task("[red]Thread-1", total=10) task2 = progress.add_task("[blue]Thread-2", total=15)
t1 = Thread(target=worker, args=(task1, 10)) t2 = Thread(target=worker, args=(task2, 15)) t1.start(); t2.start() t1.join(); t2.join()
RMI远程方法调用 word版下载Raza Microelectronics, Inc.(RMI公司)是勇于创新的信息基础架构半导体解决方案领导厂商,其产品广泛地被应用于改善不断演进的信息基础设施。在这个演进过程中,数据中心和家庭之间的连接在强度和速率方面都逐渐升级;安全和智能化已经成为每一个网络系统环境的要求;同时,边缘网络日益成为瓶颈,促使业界需要更具扩展能力及成本优势的智能网络接入方法。RMI公司为信息基础架构设计并提供多样化的解决方案,为下一代灵活的企业和数据中心应用、智能接入和数字影像系统奠定基础。 RMI远程方法调用目录 一、
替代方案:用 multiprocessing.Manager 共享进度值(适合进程间)
如果实际用的是
multiprocessing(而非threading),Progress本身不支持跨进程。此时需绕过 UI 层,用Manager.dict()或Value同步原始进度数值,再由主线程轮询更新 UI:
- 各子进程写入
shared_dict['task1'] = 7这类键值对 - 主线程在
Progress的refresh_per_second控制下定期读取并调用update(task_id, completed=shared_dict['task1']) - 注意避免频繁轮询导致 CPU 升高,建议
refresh_per_second=4起步
容易被忽略的坑:print() 和 rich.print() 混用会破坏布局
多线程中若任一线程执行了普通 print() 或未绑定到同一 Console 的 rich.print(),会强行换行、挤占进度条空间,导致显示撕裂。必须统一:
- 所有输出走同一个
console.print() - 禁用所有裸
print() - 第三方库日志若输出到 stdout,需重定向或配置其使用该
Console
线程安全的底线不是“能跑”,而是“每次刷新都看到一致、完整、不跳动的进度行”——这要求从 console 初始化、task 分配到日志输出全部收口。







