MPI_Graph_create和MPI_Cart_create函数分别用于产生通常(图)的虚拟拓扑和笛卡尔拓扑
虚拟拓扑:
虚拟拓扑可以用图来表示,每个进程代表一个点,两点之间的连线代表通信联通,但是注意MPI在任意两个进程之间都可通信,未连接的两点之间不代表无法进行通信。但是虚拟拓扑有个很致命的缺点,就是无法直观的获得进程在拓扑间的信息。
笛卡尔拓扑:
要保证你新建的笛卡尔拓扑的节点数量和你原有的通信组的节点数量相等,多了或者少了都会引起相应的错误,当reorder是true时,新的通信组内的进程会被重新编号。
关于平移得到的相连关系,如果是非循环的平移,每次移动disp就意味着将有disp个进程被移出,否则这disp个进程将补于与移动方向反向的那端。
下面是一个例子:
#include <stdio.h>
#include <mpi.h>
int main( argc, argv )
int argc;
char **argv;
{
int rank, value, size, false=0;
int right_nbr, left_nbr;
MPI_Comm ring_comm;
MPI_Status status;
MPI_Init( &argc, &argv );
MPI_Comm_size( MPI_COMM_WORLD, &size );
MPI_Cart_create( MPI_COMM_WORLD, 1, &size, &false, 1, &ring_comm );/*创建一维网格,false意味着没有周期性(两端外的进程标识为MPI_PROC_NULL),1表示可以重排序,得到的拓扑坐标相邻关系为:
MPI_PROC_NULL, 0, 1, ... , size-1 , MPI_PROC_NULL
*/
MPI_Cart_shift( ring_comm, 0, 1, &left_nbr, &right_nbr );/*通过在定义的网格上的平移得到左右侧进程的标识*/
MPI_Comm_rank( ring_comm, &rank );/*得到在新拓扑中的标识或坐标*/
MPI_Comm_size( ring_comm, &size );/*得到新通信域中进程的个数*/
do {
if (rank == 0) {/*进程0负责读入数据并向下一个进程传递数据*/
scanf( "%d", &value );
MPI_Send( &value, 1, MPI_INT, right_nbr, 0, ring_comm );/*将数据传送到右面的进程*/
}
else {
MPI_Recv( &value, 1, MPI_INT, left_nbr, 0, ring_comm,
&status );/*后面的进程从左边的进程接收数据*/
MPI_Send( &value, 1, MPI_INT, right_nbr, 0, ring_comm );/*将接收到的数据在传递给右面的进程*/
}
printf( "Process %d got %d\n", rank, value );/*各进程打印各自得到的数据*/
} while (value >= 0);/*若读入的数据非负,则继续读入并传递*/
MPI_Finalize( );
}