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



使用mpi4py,我正在运行一个 python 程序,该程序并行启动多个 fortran 进程,从 SLURM 脚本开始,使用(例如(:

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]))

与 mpirun -n 1 ...在单个 Recvbuf 阵列上需要 3 分钟- 同时在四个 Recvbuf 阵列上运行(预期并行(,在四个处理器上使用 mpirun -n 4 ... 大约需要5分钟。但是,我希望单处理器和四个处理器情况的运行时间大致相等。

py_task实际上是一个python包装器,用于启动Fortran程序:

subprocess.check_call(cmd) 

subprocess.check_call(cmd( 和 mpi4py 包之间似乎有一些交互,阻止代码并行正常运行。

我已经查找了这个问题,但似乎找不到任何有助于它的东西。是否有针对此问题的任何修复程序/解释此处发生的情况的详细说明/有关如何隔离此代码中瓶颈原因的建议?

附加说明:

该管道已从"joblib import Parallel"适应 mpi4py,其中以前没有并行运行的 subprocess.check_call(( 问题,这就是为什么我怀疑这个问题与子进程和 mpi4py 之间的交互有关。

速度变慢最初是通过添加以下内容来解决的:

导出SLURM_CPU_BIND=无

到启动作业的 slurm 脚本。

虽然上面确实提供了临时修复,但问题实际上要深得多,我将在这里提供非常基本的描述。

1( 我卸载了使用 conda 安装的 mpi4py,然后在加载英特尔 MPI 的情况下重新安装它(为我们的计算集群推荐的 MPI 版本(。在 SLURM 脚本中,我将 python 程序的启动更改为:

斯伦蟒my_prog.py .

并删除了导出...行,并且速度减慢被删除。

2( 一次启动 40 个任务时发现另一个速度变慢>。这是由于:

每次启动基于 fortran 的子进程时,请求初始资源的文件系统都会产生成本(例如,将文件作为参数提供给程序(。在我的情况下,有大量任务同时启动,每个文件可能为 ~500mb,这可能超出了集群文件系统的 IO 能力。这导致程序因启动每个子流程的速度变慢而引入大量开销。

以前的 joblib 并行化实现一次最多只使用 24 个内核,然后对文件系统的请求没有明显的瓶颈 - 因此之前没有发现性能问题。

对于 2(,我发现最好的解决方案是显着重构我的代码,以最大限度地减少启动的子进程的数量。一个非常简单的修复,但在发现文件系统上资源请求的瓶颈之前,我没有意识到。

(最后,我还要补充一点,一般不建议在线使用 mpi4py 中的子进程模块,单节点使用首选多处理模块。

最新更新