使用mpi4py,我正在运行一个python程序,该程序从SLURM脚本开始(例如)并行启动多个fortran进程:
mpirun -n 4 python myprog.py
,但是注意到myprog.py需要更长的时间来运行更多的请求任务,例如。运行myprog.py(以下代码仅显示程序的mpi部分):
comm = MPI.COMM_WORLD
size = comm.Get_size()
rank = comm.Get_rank()
data = None
if rank == 0:
data = params
recvbuf = np.empty(4, dtype=np.float64)
comm.Scatter(data, recvbuf, root=0)
py_task(int(recvbuf[0]), recvbuf[1], recvbuf[2], int(recvbuf[3]))
在单个recvbuf阵列上使用mpirun -n 1 ...进行耗时3分钟,而在四个使用mpirun -n 4 ...的处理器上运行四个Recvbuf阵列(预期是并行运行)大约需要5分钟。但是,我希望单处理器和四处理器的运行时间大致相等。
py_task实际上是使用以下程序启动fortran程序的python包装器:
subprocess.check_call(cmd)
subprocess.check_call(cmd)与mpi4py软件包之间似乎存在某种相互作用,导致代码无法并行并行运行。
我已经查找了此问题,但似乎找不到任何有助于解决该问题的方法。是否有针对此问题的任何修复程序/详细说明,以解释此处发生的情况/有关如何找出此代码中瓶颈原因的建议?
附加说明:
此管道已针对“ joblib import Parallel”中的mpi4py进行了修改,其中subprocess.check_call()并行运行没有以前的问题,这就是为什么我怀疑此问题与子流程和mpi4py之间的交互有关
答案 0 :(得分:0)
最初通过添加以下内容解决了减速问题:
导出SLURM_CPU_BIND =无
到启动作业的Slurm脚本。
尽管上述内容确实提供了临时解决方案,但问题实际上更加严重,我将在此处提供非常基本的描述。
1)我卸载了使用conda安装的mpi4py,然后在加载了Intel MPI的情况下重新安装了它(计算群集的推荐MPI版本)。然后,在SLURM脚本中,我将python程序的启动更改为:
运行python my_prog.py。
并删除了上面的export ...行,并删除了减速。
2)发现一次降低了一次启动40多个任务的速度。这是由于:
每次启动基于Fortran的子进程时,文件系统请求初始资源都会产生成本(例如,将文件作为程序的参数提供)。以我为例,有大量任务同时启动,每个文件的大小可能约为500mb,这可能超出了群集文件系统的IO功能。由于启动每个子进程的速度变慢,这导致了程序的大量开销。
以前的并行化Joblib实现一次最多只使用24个内核,因此对文件系统的请求没有明显的瓶颈,因此为什么以前没有发现性能问题。
对于2),我发现最好的解决方案是大量重构我的代码,以最大程度地减少启动的子流程的数量。这是一个非常简单的修复程序,但是在发现文件系统上资源请求的瓶颈之前我还没有意识到。
(最后,我还要补充一点,通常不建议在线使用mpi4py中的子进程模块,而多处理模块更适合单节点使用。)