如何为multiprocess(非multiprocessing)池添加tqdm进度条
问题原因
你遇到的报错和multiprocess库本身无关,是两个独立问题导致的:
- 初始的
TypeError: 'module' object is not callable是tqdm导入错误:import tqdm导入的是tqdm模块本身,模块不能被直接调用,自然无法通过tqdm(xxx)创建进度条。 - 就算修复导入问题,直接把tqdm包装的可迭代对象传给
pool.map也无法得到正确的进度显示:pool.map会在主进程先遍历完整个输入可迭代对象、完成所有任务的拆分和提交后才会开始执行子进程任务,此时tqdm进度条会在任务提交瞬间就跑到100%,完全无法反映任务的实际执行进度。
适配
multiprocess第三方库的解决方案 以下方案完全兼容notebook环境,不会触发标准库multiprocessing常见的属性错误、序列化错误,不需要安装额外依赖:
使用pool.imap替代pool.map,将tqdm进度条包裹在imap返回的结果迭代器外层,每收到一个子进程完成的返回值就更新一次进度,逻辑稳定可靠。
完整可运行代码:
from multiprocess import Pool from time import sleep # 本地脚本环境使用这个导入 from tqdm import tqdm # Jupyter Notebook环境替换为下面的导入,获得适配notebook的美观进度条 # from tqdm.notebook import tqdm def long_calculation(run): print(f'Starting run {run}') sleep(5) print(f'Ending run {run}') return run vars_to_iterate = range(10) if __name__ == "__main__": with Pool(processes=6) as pool: # 任务量较大时可调大chunksize提升分发性能,比如chunksize=2 # 手动指定total避免可迭代对象无__len__方法时进度条无法显示总进度 list(tqdm( pool.imap(long_calculation, vars_to_iterate, chunksize=1), total=len(vars_to_iterate) ))
可选说明
- 如果不需要按任务提交顺序收集结果,可以将
pool.imap替换为pool.imap_unordered,进度更新逻辑完全一致,执行效率更高。 - 必须用
list()包裹tqdm迭代器:imap返回的是懒加载迭代器,只有主动遍历拉取结果时才会触发进度条更新,否则所有任务会在后台执行但进度条不会动。 - 该方案完全适配
multiprocess第三方库的接口逻辑,不需要修改任何序列化、进程启动相关的配置。
内容的提问来源于stack exchange,提问作者Oion Akif
相关产品推荐
相关产品推荐

