在MPI_Comm_split之后如何分配句柄?

时间:2014-03-29 22:39:17

标签: c parallel-processing multiprocessing mpi

说,我有8个进程。当我执行以下操作时,MPU_COMM_WORLD通信器将被分成两个通信器。具有偶数id的进程将属于一个通信器,具有奇数id的进程将属于另一个通信器。

color=myid % 2;
MPI_Comm_split(MPI_COMM_WORLD,color,myid,&NEW_COMM);
MPI_Comm_rank( NEW_COMM, &new_id);

我的问题是这两个传播者的处理方式在哪里。拆分之后,处理器的ID为0 1 2 3 4 5 6 7将变为0 2 4 6 | 1 3 5 7。

现在,我的问题是:假设我想在特定的通信器中发送和接收,比如主持偶数ID的那个,然后当我使用错误的通信器从0到2发送消息时,消息可能最终在第二个沟通者,这是对的吗?提前谢谢您的澄清!

if(new_id < 2){

    MPI_Send(&my_num, 1, MPI_INT,  2 + new_id, 0, NEW_COMM);
    MPI_Recv(&my_received, 1, MPI_INT, 2 + new_id, 0, NEW_COMM, MPI_STATUS_IGNORE);         

}
else
{
    MPI_Recv(&my_received, 1, MPI_INT, new_id - 2, 0, NEW_COMM, MPI_STATUS_IGNORE);         
    MPI_Send(&my_num, 1, MPI_INT, new_id - 2 , 0, NEW_COMM);


}

完整代码

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <math.h>
int main(argc,argv)
int argc;
char *argv[];

{
    int myid, numprocs;
    int color,Zero_one,new_id,new_nodes;
    MPI_Comm NEW_COMM; 
    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
    MPI_Comm_rank(MPI_COMM_WORLD,&myid);


    int my_num, my_received;

       int old_id;


    switch(myid){

        case 0:
            my_num = 0;
            old_id = 0;

        break;


        case 1:
            my_num = 1;
            old_id = 1;

        break;

        case 2:
            my_num = 2;
            old_id = 2;

        break;

        case 3:
            my_num = 3;
            old_id = 3;

        break;

        case 4:
            my_num = 4;
            old_id = 4;

        break;

        case 5:
            my_num = 5;
            old_id = 5;

        break;

        case 6:
            my_num = 6;
            old_id = 6;

        break;

        case 7:
            my_num = 7;
            old_id = 7;

        break;


    }



    color=myid % 2;
    MPI_Comm_split(MPI_COMM_WORLD,color,myid,&NEW_COMM);
    MPI_Comm_rank( NEW_COMM, &new_id);
    MPI_Comm_rank( NEW_COMM, &new_nodes);



       //  0 1 2 3     4 5 6 7  //After splits we have these nums for 8 processors
       //  2 3 0 1     6 7 4 5  //After the below exchange we should have this...each two elements in each communicator will exchange to next two elements in that same communicator




        if(new_id < 2){

            MPI_Send(&my_num, 1, MPI_INT,  2 + new_id, 0, NEW_COMM);
            MPI_Recv(&my_received, 1, MPI_INT, 2 + new_id, 0, NEW_COMM, MPI_STATUS_IGNORE);         

        }
        else
        {
            MPI_Recv(&my_received, 1, MPI_INT, new_id - 2, 0, NEW_COMM, MPI_STATUS_IGNORE);         
            MPI_Send(&my_num, 1, MPI_INT, new_id - 2 , 0, NEW_COMM);


        }



    printf("old_id= %d received num= %d\n", old_id, my_received);


    MPI_Finalize();

}

1 个答案:

答案 0 :(得分:0)

我已经编辑了你的问题,使其更加清晰。另外,我修复了与调用MPI_Comm_split创建的两个新通信器相关的ID。

第一个问题。调用MPI_Comm_split之后的单个进程最多可以获得一个新创建的通信器的一个句柄(实际上,对于传递MPI_UNDEFINED作为颜色参数值的进程,实际上,返回的通信器可能等于MPI_COMM_NULL)。这就是为什么初学者通常不理解这个调用的语义的原因:MPI_Comm_split是一个集体调用,因此,它必须由原始通信器中的所有进程调用。因此,每个进程调用一次,但该函数返回$ k $ communicators,具体取决于所有进程提供的颜色参数的值,将进程划分为$ k $ groups。如果您对这种强大的机制不满意并且想要只创建一个通信器,那么只需提供MPI_UNDEFINED作为进程所进行的每个调用中颜色参数的值,该进程必须不属于新创建的通信器。但是,您应该使用其他可用的功能来创建通信器,而不是MPI_Comm_split。

第二个问题。如果语义现在已经清除,您将立即认识到使用MPI_Comm_split为点对点或集体通信返回的通信器的进程永远不会与作为MPI_Comm_split返回的另一个通信器的一部分的进程交换数据。传播者提供了不同的传播者世界,因为每个传播者都有一组不同的过程。

现在,即使由属于偶数ids通信器的进程调用,您的代码段也不起作用。为什么?因为在new_id&lt;将从新通信器中具有等级0的进程正确地发送到新通信器中具有等级2的进程,并且新通信器中具有等级0的进程将从新通信器中具有等级2的进程接收。 但是,else分支存在缺陷。实际上,在新通信器中具有偶数等级&gt; = 2的所有进程将执行它,而不仅仅是具有等级2的进程。在这种情况下,该分支将由新的等级2,4和6的进程执行。甚至ids沟通者。当然,排名为4和6的进程将永远挂起,分别阻止进程2和4从未发送的消息。

最后,由于相同的代码也将由另一个新创建的通信器中具有奇数id的进程执行,因此具有等级1的进程将尝试从进程3发送和接收,并且在else分支中具有等级3的进程,5和7也将尝试发送和接收。在这种情况下,进程5和7将永远挂起,分别阻止进程3和5从未发送的消息。

如果要在级别为0和2的进程之间交换数据,则可以轻松修复代码。只需使用显式ids 0和2,并按如下所示重写if:

if(!new_id){
    MPI_Send(&my_num, 1, MPI_INT,  2, 0, NEW_COMM);
    MPI_Recv(&my_received, 1, MPI_INT, 2 + new_id, 0, NEW_COMM, MPI_STATUS_IGNORE);
}

if(new_id == 2){

    MPI_Recv(&my_received, 1, MPI_INT, 0, 0, NEW_COMM, MPI_STATUS_IGNORE);         
    MPI_Send(&my_num, 1, MPI_INT, 0, 0, NEW_COMM);

}