gpt4 book ai didi

c - MPI_Comm_split 之后句柄如何分配?

转载 作者:太空宇宙 更新时间:2023-11-04 04:44:20 24 4
gpt4 key购买 nike

比如说,我有 8 个进程。当我执行以下操作时,MPU_COMM_WORLD 通信器将分成两个通信器。 id 为偶数的进程将属于一个 communicator,id 为奇数的进程将属于另一个 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 | 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();

}

最佳答案

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

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

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

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

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

如果您想在等级为 0 和 2 的进程之间交换数据,代码很容易修复。只需使用显式 ID 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);

}

关于c - MPI_Comm_split 之后句柄如何分配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22737842/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com