MPI在根进程上收集数组

7

我还不熟悉MPI。我有4个进程:1到3进程填充一个向量并将其发送到进程0,进程0将这些向量收集成一个非常长的向量。我有能够运行的代码(太长无法发布),但是进程0的接收操作很笨拙而且非常慢。

简单来说,该代码执行以下操作:

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();

原来,endcomm-startcomm 占总时间的50%(相较于完成程序需要1.5秒而言,占用了0.7秒)。 有没有更好的方法从进程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);

出现了相同的缓慢表现。这是否与根进程在尝试下一个接收之前“等待”每个单独接收完成有关?还是说这种想法是错误的?


只是一个快速的评论 - C++绑定在当前MPI标准版本2.2中已被弃用,并将在即将推出的MPI 3.0中完全删除。出于可移植性原因,建议您学习并使用C接口。 - Hristo Iliev
你的程序中 nm 的规模有多大?你的机器之间有什么样的连接关系? - suszterpatt
Hristo,谢谢 - 我把我的代码改成了C接口。 - covstat
suszterpatt-- n=3500,m=7,所以n*m=24,500。我不知道如何确定连接。如果有帮助的话,我现在正在我的笔记本电脑Macbook Pro 2.2 GHz Core i7上测试这段代码,但很快将在Sun Grid Engine集群上运行它。 - covstat
@covstat,由于您使用的是共享内存,所以不应该出现连接问题。您期望看到什么样的性能?无论您使用哪种MPI操作,这种数据收集总是比邻居之间的交换慢。我不熟悉Mac,所以这可能也是操作系统/编译器/MPI构建问题,这超出了我的知识范围。 - milancurcic
请注意,在程序的第一个版本(发送/接收)中,进程0按照您的for循环指定的顺序等待消息。另一方面,MPI_Gather将按照它们到达的任何顺序接收消息,因此MPI_Gather可能更有效,但这并不保证。 - milancurcic
1个回答

6

是的,MPI_Gather可以完全做到这一点。来自MPI_Gather页面的说明:

int MPI_Gather(void *sendbuf, int sendcnt, MPI_Datatype sendtype, 
               void *recvbuf, int recvcnt, MPI_Datatype recvtype, 
               int root, MPI_Comm comm)

在这里,sendbuf是每个进程上的数组(my_array)。recvbuf是接收进程中的长数组(all_arrays),其中短数组正在被聚集。接收进程上的短数组将被复制到其在长数组中的连续位置,因此您不需要担心自己进行复制。每个进程的数组将在长数组中连续排列。
编辑:
如果接收进程在聚集中没有贡献sendbuf,则可以使用MPI_Gatherv代替(感谢@HristoIliev指出这一点)。

3
由于rank 0不会发送给自己,因此最好使用MPI_Gatherv() - Hristo Iliev
3
@RestlessC0bra,“MPI_Gathev”允许指定来自组中每个排名的数据量,特别地,可以指定没有任何数据(0)。而这一点在“MPI_Gather”中是不可能实现的,因此我才会这么评论。 - Hristo Iliev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接