Mpi4py代码不会停止运行

Com*_*ner 1 python parallel-processing hpc cluster-computing mpi4py

我正在使用一个非常基本的 python 代码(文件名:)test_mpi.py来尝试使用 mpi4py 在 python 中进行并行编程。我想做的是拥有一个所有条目都为零的二维 numpy 数组。然后使用集群中的特定处理器来增加 numpy 数组的特定元素的值。

具体来说,我有一个 3*3 numpy 矩阵 ( mat),其中所有元素均为零。当我的代码完成运行(跨多个处理器)后,我希望矩阵如下所示:

mat = [[ 1.  2.  3.]
       [ 4.  5.  6.]
       [ 7.  8.  9.]]
Run Code Online (Sandbox Code Playgroud)

这是一个相当简单的任务,我希望我的代码在几分钟内完成运行(如果不是更短的时间)。我的代码持续运行很长时间并且不会停止执行(最终我必须在几个小时后删除该作业。)

这是我的代码:

from __future__ import division
from mpi4py import MPI
import os
import time
import numpy as np

comm = MPI.COMM_WORLD
nproc = comm.Get_size()
rank = comm.Get_rank()

start_time = time.time()

mat = np.zeros((3,3))

comm.bcast([ mat , MPI.DOUBLE], root=0)


for proc in range(1, nproc):
    if rank == proc:
        print "I'm processor: ", rank
        var = proc
        comm.send( var, dest=0, tag = (proc*1000) ) 
        print "Processor: ", rank, " finished working."


if rank == 0:
    print "Hello! I'm the master processor, rank: ", rank 
    for i in range(0,dim):
        for j in range(0, dim):
            proc = ((i*j)+1)
            mat[i,j] += comm.recv(source=proc, tag=(proc*1000) )


     np.savetxt('mat.txt', mat) 



print time.time() - start_time
Run Code Online (Sandbox Code Playgroud)

这是我用于执行此 python 代码的作业脚本:

#!/bin/sh

#PBS -l nodes=2:ppn=16
#PBS -N test_mpi4py
#PBS -m abe
#PBS -l walltime=168:00:00
#PBS -j eo
#PBS -q physics

cd $PBS_O_WORKDIR
export OMP_NUM_THREADS=16
export I_MPI_PIN=off
echo 'This job started on: ' `date`

/opt/intel/impi/2018.0.128/intel64/bin/mpirun -np 32 python test_mpi.py
Run Code Online (Sandbox Code Playgroud)

我用来qsub jobscriptname.sh运行作业脚本。我在这里缺少什么?我将不胜感激这里的任何帮助。

Dmi*_*rov 5

您的代码未完成,因为某些 MPI 通信未完成。

MPI 要求每次发送都应该有一次接收。rank == proc您的第一个循环由每个 MPI 进程等级独立执行,除了等级之外,每个等级的条件将恰好满足一次0,因此comm.send将被执行nproc - 1多次。你的第二个循环被执行了dim * dim次。因此comm.recv也会被执行dim*dim多次。除非nproc - 1 == dim * dim。该要求将无法得到满足,并且某些recv操作send将无限期地等待完成。对于您的示例31 != 9,因此只有超过挂起时间后,通信才会完成。

为了修复这个错误,让我们稍微澄清一下算法。因此,我们希望从 1 到 9 的每一列负责 3x3 矩阵中的一个元素。每个进程级别都会发布comm.send请求。进程等级 0 按一定顺序接收请求并将其存储在矩阵的相应元素中。其余的队伍如果有空的话什么也不做。

让我们介绍一下三个变化:

  1. 初始化值dim
  2. 将检查处理器等级 0 的条件运算符移出循环
  3. 修复当前不正确的元素对应的排名计算mat[i,j](例如,对于中心元素,mat[1,1]排名应为 5,而不是 1 * 1 + 1 = 2)

代码

这是我修改后得到的结果:

from __future__ import division
from mpi4py import MPI
import os
import time
import numpy as np

comm = MPI.COMM_WORLD
nproc = comm.Get_size()
rank = comm.Get_rank()

start_time = time.time()

dim = 3
mat = np.zeros((dim,dim))

comm.bcast([ mat , MPI.DOUBLE], root=0)

if rank > 0:
    if rank <= dim * dim:
        print "I'm processor: ", rank
        var = rank
        req = comm.send( var, dest=0, tag = (rank*1000) )
    print "Processor: ", rank, " finished working."
else:
    print "Hello! I'm the master processor, rank: ", rank 
    for i in range(0,dim):
        for j in range(0, dim):
            proc = ((i*dim)+j)+1
            if proc < nproc:
                mat[i,j] += comm.recv(source=proc, tag=(proc*1000) )
    np.savetxt('mat.txt', mat)
Run Code Online (Sandbox Code Playgroud)

输出

这是输出:

mpirun -np 5 python mpi4.py 
Run Code Online (Sandbox Code Playgroud)

保存到mat.txt以下矩阵

1.000000000000000000e+00 2.000000000000000000e+00 3.000000000000000000e+00
4.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00
0.000000000000000000e+00 0.000000000000000000e+00 0.000000000000000000e+00
Run Code Online (Sandbox Code Playgroud)

mpirun -np 32 python mpi4.py 
Run Code Online (Sandbox Code Playgroud)

保存到mat.txt以下矩阵

1.000000000000000000e+00 2.000000000000000000e+00 3.000000000000000000e+00
4.000000000000000000e+00 5.000000000000000000e+00 6.000000000000000000e+00
7.000000000000000000e+00 8.000000000000000000e+00 9.000000000000000000e+00
Run Code Online (Sandbox Code Playgroud)

10 是产生正确结果的最小进程等级数。