MPI在根进程上收集数组

cov*_*tat 4 c mpi

我是MPI的新手.我有4个进程:进程1到3填充向量并将其发送到进程0,进程0将向量收集到一个非常长的向量中.我的代码有效(发布时间太长),但进程0的recv操作很笨拙而且非常慢.

在摘要中,代码执行以下操作:

MPI::Init();
int id = MPI::COMM_WORLD.Get_rank();

if(id>0) {
    double* my_array = new double[n*m]; //n,m are int
    Populate(my_array, id);
    MPI::COMM_WORLD.Send(my_array,n*m,MPI::DOUBLE,0,50);
}

if(id==0) {
    double* all_arrays = new double[3*n*m];
    /* Slow Code Starts Here */
    double startcomm = MPI::Wtime();
    for (int i=1; i<=3; i++) {
    MPI::COMM_WORLD.Recv(&all_arrays[(i-1)*m*n],n*m,MPI::DOUBLE,i,50);
    }
    double endcomm = MPI::Wtime();
    //Process 0 has more operations...
}
MPI::Finalize();
Run Code Online (Sandbox Code Playgroud)

事实证明,它endcomm - startcomm占总时间的50%(0.7秒,而程序完成时间为1.5秒).

有没有更好的方法从进程1-3接收向量并将它们存储在进程0中all_arrays

我检查了MPI :: Comm :: Gather,但我不确定如何使用它.特别是,它是否允许我指定进程1的数组是all_arrays中的第一个数组,进程2的数组是第二个数组,等等?谢谢.

编辑:我删除了"慢"循环,而是将以下内容放在"if"块之间:

MPI_Gather(my_array,n*m,MPI_DOUBLE,
    &all_arrays[(id-1)*m*n],n*m,MPI_DOUBLE,0,MPI_COMM_WORLD);
Run Code Online (Sandbox Code Playgroud)

导致同样缓慢的表现.这是否与根进程在尝试下一个进程之前"等待"每个接收完成的事实有关?或者这不是思考它的正确方法吗?

mil*_*cic 5

是的,MPI_Gather会做到这一点.从对ANL页MPI_Gather:

int MPI_Gather(void *sendbuf, int sendcnt, MPI_Datatype sendtype, 
               void *recvbuf, int recvcnt, MPI_Datatype recvtype, 
               int root, MPI_Comm comm)
Run Code Online (Sandbox Code Playgroud)

sendbuf是每个进程(my_array)上的数组.recvbufall_arrays正在收集短数组的接收进程的long array().接收进程中的短数组正被复制到长数组中的连续位置,因此您无需担心自己执行此操作.每个进程的数组将在长数组中连续排列.

编辑:

如果接收过程在收集过程中没有提供sendbuf,您可能需要使用MPI_Gatherv(感谢@HristoIliev指出这一点).

  • 由于0级不发送给自己,因此使用`MPI_Gatherv()`会更好. (3认同)
  • @ RestlessC0bra,`MPI_Gathev`允许指定来自组中每个等级的数据量,特别是没有数据(0).这是"MPI_Gather"无法做到的,因此我的评论. (2认同)