使用mpi4py时并行启动子进程时速度变慢

时间:2018-08-29 16:32:49

标签: python subprocess mpi4py

使用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之间的交互有关

1 个答案:

答案 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中的子进程模块,而多处理模块更适合单节点使用。)