为什么Python multiprocessing任务耗时远高于单进程,如何解决?
问题1解答
这种耗时增长不是常规多进程开销导致的,核心原因有两个:
- numpy多线程资源竞争:默认安装的numpy(不管是OpenBLAS还是MKL版本)都会自动调用多线程执行矩阵运算,单任务就能占满多个CPU核心。你开7个进程的情况下,7个进程各自都会启动多线程抢8个核心的算力,频繁的上下文切换会导致所有任务的执行效率暴跌,这才是耗时翻几倍的核心原因。
- IO冲突:你提供的示例代码中所有进程都会往同一个
f.png文件写数据,多进程同时写入同一个文件会触发磁盘IO竞争,额外拉长执行时间。你的实际业务代码如果也存在多个进程写同个文件、读同个大文件的逻辑,也会进一步放大耗时。
常规multiprocessing的进程启动、任务调度开销占比通常不会超过单任务耗时的5%,不可能导致8倍的耗时增长。
问题2解答
完全可以实现N个任务跑在N个核心上,总耗时和单任务基本持平,只需要做以下修改:
第一步:关闭numpy等科学计算库的内置多线程
在导入numpy、scipy等库之前,先设置环境变量强制所有计算库单线程运行:
import os # 强制所有科学计算库单线程执行,必须写在导入numpy之前 os.environ["OMP_NUM_THREADS"] = "1" os.environ["OPENBLAS_NUM_THREADS"] = "1" os.environ["MKL_NUM_THREADS"] = "1" os.environ["VECLIB_MAXIMUM_THREADS"] = "1" os.environ["NUMEXPR_NUM_THREADS"] = "1" import numpy as np import matplotlib.pyplot as plt from multiprocessing import Pool import time
第二步:避免IO冲突
所有输出文件按任务ID区分,不要多进程写同一个文件,示例代码里的保存逻辑修改为:
plt.savefig(f'f_{x}.png')
第三步:(可选)替换多进程实现方式
如果调整后还是有不符合预期的开销,可以直接在Python中用subprocess启动独立的Python进程执行单任务代码,逻辑和SLURM的array任务完全一致,没有进程池的额外调度开销:
import subprocess task_num = 100 process_list = [] for i in range(task_num): # 每个任务启动独立Python进程执行,传入任务ID作为参数 p = subprocess.Popen(["python", "single_task.py", str(i)]) process_list.append(p) # 等待所有任务执行完成 for p in process_list: p.wait()
调整后你再做测试,N=7的总耗时会降到和单任务耗时基本一致。
内容的提问来源于stack exchange,提问作者Ptheguy
相关产品推荐
相关产品推荐

