Python 3.6中multiprocessing结合tqdm进度条失效问题求助
问题原因
你的进度条无法正常工作的核心问题在于 mp.Pool.starmap() 是阻塞式方法——它会等待所有子进程完成全部任务后,才一次性返回完整的结果列表。这就导致 tqdm.tqdm() 遍历的是已经完全生成好的列表,根本没有机会实时追踪任务的执行进度,自然看不到动态更新的进度条。
解决方案
下面是两种适配多进程场景的可行方案,都能让 tqdm 进度条正常工作:
方案1:使用 imap() + functools.partial 绑定固定参数
imap() 是迭代器式的方法,会在子进程完成单个任务后立即返回结果,刚好适配 tqdm 的实时更新需求。我们可以用 functools.partial 把固定参数 fix1 和 fix2 提前绑定到函数 f 上:
import multiprocessing as mp import tqdm from functools import partial def f(dynamic, fix1, fix2): return dynamic + fix1 + fix2 if __name__ == "__main__": # 多进程必须加这个代码块,避免Windows下递归启动问题 N = 2 fix1 = 5 fix2 = 10 dynamic = range(10) # 绑定固定参数,让函数只接收dynamic一个参数 f_partial = partial(f, fix1=fix1, fix2=fix2) with mp.Pool(processes=N) as p: # 用imap遍历任务结果,tqdm实时追踪进度 for _ in tqdm.tqdm(p.imap(f_partial, dynamic), total=len(dynamic)): pass
方案2:使用 starmap_async() + 回调更新进度条
如果更倾向于保留 starmap 风格的参数传递方式,可以用 starmap_async() 配合回调函数,手动更新 tqdm 的进度:
import multiprocessing as mp import tqdm def f(dynamic, fix1, fix2): return dynamic + fix1 + fix2 if __name__ == "__main__": N = 2 fix1 = 5 fix2 = 10 dynamic = range(10) tasks = [(d, fix1, fix2) for d in dynamic] with mp.Pool(processes=N) as p: # 初始化进度条 with tqdm.tqdm(total=len(tasks)) as pbar: # 定义回调函数:每完成一个任务就更新一次进度条 def update_progress(_): pbar.update(1) # 提交异步任务,绑定回调 result = p.starmap_async(f, tasks, callback=lambda _: None) # 循环检查任务完成状态,确保回调有机会执行 while not result.ready(): pass
额外注意事项
- 务必加上
if __name__ == "__main__":代码块,尤其是在 Windows 系统下,否则多进程会出现递归启动的错误(Python 3.6 严格要求这一点)。 - 确保你的
tqdm版本兼容 Python 3.6,建议安装tqdm>=4.23.0(该版本及以上对 Python 3.6 支持良好)。
内容的提问来源于stack exchange,提问作者Mathieu
相关产品推荐
相关产品推荐

