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

如何在multiprocessing函数内用tqdm追踪for循环进度?

解决Jupyter Notebook多进程+外部exe的实时多进度条监控问题

针对你在Jupyter中用multiprocessing启动多个外部exe实例,需要实时监控每个实例迭代进度的需求,以下是可行的解决方案:

核心思路

利用**进程间队列(Queue)**传递进度信息:子进程仅负责收集进度数据并发送到队列,主进程启动专门线程监听队列,更新对应的tqdm进度条。这种方式避免了直接传递tqdm实例导致的序列化错误,同时确保进度条在Jupyter前端正确显示(而非输出到Anaconda Prompt)。

具体实现

1. 修改外部函数文件Functions.py

让函数接收进度队列作为参数,每次迭代完成后发送进度数据:

def run_exe_instance(args, progress_queue):
    import os
    import subprocess
    # 从args中解析所需参数(根据你的实际参数调整)
    directory, notebookFolder, number_of_exe_iterations, filename = args
    
    os.chdir(directory)
    # 开启text=True,直接处理字符串输出,避免字节流判断问题
    exe_process = subprocess.Popen(["program.exe"], shell=True, stdout=subprocess.PIPE, text=True)
    os.chdir(notebookFolder)
    
    for i1 in range(number_of_exe_iterations):
        line = exe_process.stdout.readline()
        if line:
            # 发送进度消息:(任务标识, 当前进度, 总进度)
            progress_queue.put((filename, i1 + 1, number_of_exe_iterations))
    
    # 确保外部进程完全结束
    exe_process.wait()
    # 发送完成信号
    progress_queue.put((filename, number_of_exe_iterations, number_of_exe_iterations))
    print(f"{filename} 已完成!")

2. 修改Jupyter主脚本

创建共享队列、初始化进度条、启动监控线程、管理进程池:

import multiprocessing as mp
from multiprocessing import Manager
from tqdm.notebook import tqdm  # 适配Jupyter的tqdm版本
import Functions as f

def monitor_progress(progress_queue, progress_bars):
    """监听队列,更新进度条的线程函数"""
    while True:
        msg = progress_queue.get()
        if msg is None:  # 收到结束信号,退出线程
            break
        filename, current, total = msg
        # 更新对应进度条的当前值并刷新
        progress_bars[filename].n = current
        progress_bars[filename].refresh()
        # 进度完成时关闭进度条
        if current >= total:
            progress_bars[filename].close()

if __name__ == "__main__":
    __spec__ = None  # Jupyter多进程bug修复
    
    # 准备任务参数列表(根据你的实际需求调整)
    args_list = [
        ("path/to/dir1", "/path/to/notebook/folder", 100, "任务A"),
        ("path/to/dir2", "/path/to/notebook/folder", 150, "任务B")
    ]
    
    with Manager() as manager:
        # 创建跨进程共享的队列
        progress_queue = manager.Queue()
        
        # 初始化每个任务的进度条,设置不同position避免重叠
        progress_bars = {}
        bar_pos = 0
        for args in args_list:
            filename = args[3]
            total_steps = args[2]
            progress_bars[filename] = tqdm(total=total_steps, desc=filename, position=bar_pos)
            bar_pos += 1
        
        # 启动进度监控线程(设为守护线程,主进程结束时自动退出)
        monitor_thread = mp.Process(target=monitor_progress, args=(progress_queue, progress_bars))
        monitor_thread.daemon = True
        monitor_thread.start()
        
        # 启动进程池,将队列作为参数传入每个任务
        pool = mp.Pool(len(args_list))
        # 给每个任务参数追加队列参数,适配starmap的传参格式
        pool.starmap(f.run_exe_instance, [(args + (progress_queue,)) for args in args_list])
        
        # 发送结束信号给监控线程
        progress_queue.put(None)
        monitor_thread.join()
        
        # 关闭进程池
        pool.close()
        pool.join()
        
        # 清理剩余进度条
        for bar in progress_bars.values():
            bar.close()

关键细节说明

  1. 进程间通信:用Manager.Queue而非普通mp.Queue,确保队列能在Pool的子进程间正常共享。
  2. Jupyter适配:使用tqdm.notebook.tqdm而非普通tqdm,进度条会在Jupyter前端正确渲染,不会输出到启动终端。
  3. 进度条定位:通过position参数设置每个进度条的位置,避免多进度条互相覆盖。
  4. 序列化问题:子进程仅传递简单的字符串和数字(进度数据),无需传递tqdm实例,彻底避开pickle序列化错误。

内容的提问来源于stack exchange,提问作者Arthur Booling

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 03:12:31