MPI_Comm_split之后如何分配句柄? [英] how are handles distributed after MPI_Comm_split?

查看:183
本文介绍了MPI_Comm_split之后如何分配句柄?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Say, i have 8 processes. When i do the following, the MPU_COMM_WORLD communicator will be splitted into two communicators. The processes with even ids will belong to one communicator and the processes with odd ids will belong to another communicator.

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

我的问题是,这两个传播者的手柄在哪里.拆分之后,以前为0 1 2 3 4 5 6 7的处理器的id将变为0 2 4 6 | 0. 1 3 5 7.

My question is where is the handle for these two communicators. After the split the ids of processors which before were 0 1 2 3 4 5 6 7 will become 0 2 4 6 | 1 3 5 7.

现在,我的问题是:假设我想在一个特定的通信器中发送和接收,说一个主持偶数id的通信器,那么当我使用错误的通信器从0到2发送一条消息时,该消息可能会最终出现在第二沟通者,这是正确的吗?预先感谢您的澄清!

Now, my question is: suppose I want to send and receive in a particular communicator, say the one hosting the even ids, then when i send a message from 0 to 2 using the wrong communicator the message could end up in the second communicator, is this correct? Thank you in advance for clarification!

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

}

推荐答案

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

I have edited your question, making it clearer. Also, I fixed the ids related to the two new communicators created by the call to MPI_Comm_split.

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

First question. A single process after the call to MPI_Comm_split can get at most ONE handle to a newly created communicator (at most, indeed, the returned communicator may be equal to MPI_COMM_NULL for processes passing MPI_UNDEFINED as the value for the color parameter). This is the reason why beginners typically do not understand the semantics of this call: MPI_Comm_split is a collective call, and, as such, it must be called by all of the processes in the original communicator. So, every process calls it once, but the function returns $k$ communicators, depending on the values of the color parameter supplied by all of the processes, partitioning the processes into $k$ groups. If you are NOT comfortable with this powerful mechanism and want to create just one communicator, simply supply MPI_UNDEFINED as the value of the color parameter in every call made by a process which must not belong to the newly created communicator. But then, you should use other available functions that allow creation of a communicator, not MPI_Comm_split.

第二个问题.如果现在语义清楚了,您将立即认识到,使用MPI_Comm_split返回的通信器进行点对点或集体通信的进程永远不能与MPI_Comm_split返回的另一个通信器的进程交换数据.传播者提供了不同的传播者范围,因为每个传播者都关联了不同的进程组.

Second question. If the semantics is now clear, you will immediately recognize that a process using the communicator returned by MPI_Comm_split for point-to-point or for collective communications can NEVER exchange data with processes being part of another communicator returned by MPI_Comm_split. The communicators provide a different universe of communicators, since each communicator has associated a different group of processes.

现在,即使属于偶数id通信器的进程调用了您的代码段,也无法使用.为什么 ?因为当new_id<时执行的代码2将正确地从新通信器中具有等级0的进程发送到新通信器中具有等级2的进程,并且新通信器中具有等级0的进程将从新通信器中具有等级2的进程接收. 但是,else分支存在缺陷.实际上,新通信器中所有偶数等级> = 2的进程都将执行它,而不仅仅是具有等级2的进程.在这种情况下,此分支将由新偶数中具有等级2、4和6的进程执行. ids传播者.当然,等级为4和6的进程将永远挂起,分别阻塞进程2和4从未发送过的消息.

Now, your code snippet will NOT work, even if called by processes belonging to the even ids communicator. Why ? Because the code executed when new_id < 2 will correctly send from process with rank 0 in the new communicator to the process with rank 2 in the new communicator, and the process with rank 0 in the new communicator will receive from process with rank 2 in the new communicator. However, the else branch is flawed. Indeed, ALL of the processes with even rank >= 2 in the new communicator will execute it, not just the process with rank 2. In this case, this branch will be executed by processes with rank 2, 4 and 6 in the new even ids communicator. Of course, the processes with ranks 4 and 6 will hang forever, blocking respectively for a message never sent by processes 2 and 4.

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

Finally, since the same code will also be executed by processes with odd id in the other newly created communicator, the process with rank 1 will try to send and receive from process 3, and in the else branch the processes with ranks 3, 5 and 7 will try to send and receive as well. In this case, processes 5 and 7 will hang forever, blocking respectively for a message never sent by processes 3 and 5.

如果要在等级0和2的进程之间交换数据,则代码很容易修复.只需使用显式ID 0和2并重写if,如下所示:

The code is easily fixed if you want to exchange data between the processes with rank 0 and 2. Simply use the explicit ids 0 and 2 and rewrite the if as follows:

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

}

这篇关于MPI_Comm_split之后如何分配句柄?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆