集合通信是包含在通信因子中的所有进程都参加操作
集合通信一般实现三个功能
- 通信:组内数据的传输
- 同步:组内所有进程在特定的地点在执行进度上取得一致
- 计算:对给定的数据完成一定的操作
集合操作的三种类型:
- 通信:广播(broadcast)、分散(scatter)、收集(gather)、全互换(alltoall)等
- 同步(barrier):集合中所有进程都到达后,每个进程再接着运行
- 规约(reduction):集合中的其中一个进程收集所有进程的数据并计算(如:求最大值、求最小值、加、乘等)
1. 组通信的通信功能
1.1 一对多集合通信函数
一对多通信,在一个通信域内,以其中一个进程为根进程,向其他所有进程(包括该进程自身)发送数据。包括MPI_Bcast(广播)和MPI_Scatter(散发)两种操作方式。
1.1.1 广播 MPI_Bcast
int MPI_Bcast ( void *buf,int count, MPI_Datatype datatype, int root, MPI_Comm comm )
- 根进程将消息广播发送到通信域内所有其他进程(包括该进程自身)
- 所有进程(包括自身)都使用同一个通信域 comm 和根进程标识 root
- 其他进程指定的通信元素个数、数据类型必须与跟进程指定的通信 元素个数、数据类型保持一致
/*
* 根进程(进程0)向组内的每个进程广播1个整型数据。
*/
#include<stdio.h>
#include"mpi.h"
void main(int argc,char *argv[])
{
int rank,size;
int value;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&size);
if(rank==0)
{
fprintf(stderr,"Process %d: Please input value: \n",rank);
scanf("%d",&value);
}
MPI_Bcast(&value,1,MPI_INT,0,MPI_COMM_WORLD);
fprintf(stderr,"Process %d received value %d \n",rank,value);
MPI_Finalize();
}
运行结果(图片传不上来。。。)
[root@dl1 mpi]# mpirun -np 4 ./test-13-2
Process 0: Please input value:
2000000
Process 0 received value 2000000
Process 1 received value 2000000
Process 2 received value 2000000
Process 3 received value 2000000
[root@dl1 mpi]# mpirun -np 4 ./test-13-2
Process 0: Please input value:
2000000
Process 0 received value 2000000
Process 1 received value 2000000
Process 2 received value 2000000
Process 3 received value 2000000
1.1.2 散发 MPI_Scatter/MPI_Scatterv
int MPI_Scatter ( void *sendbuf, int sendcount, MPI_Datatype datatype, void *recvbuf, int recvcount, MPI_Datatype datatype, int root, MPI_Comm comm )
与广播不同,散发操作的root向其他进程发送的数据可以是不同的。对于非根进程,发送消息缓冲区被忽略。接受数据元素的个数、类型必须与所有接受数据元素的个数类型相同。
/*
* 根进程(进程0)向组内的每个进程分散10个整型数据。
*/
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <time.h>
void main(int argc, char *argv[])
{
int rank,size;
int recvArray[10],*sendbuf;
int root = 0;
int recvnum = 10,sendnum;
int i;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&size);
sendnum = recvnum * size;
// root进程中的数组sendbuf分配内存并赋初值(1~9之间的随机整数)
srand((unsigned)time(NULL));
if(rank == root)
{
sendbuf = (int *)malloc(sendnum * sizeof(int)); // 动态分配内存
for(i=0;i<sendnum;i++)
sendbuf[i] = rand()%9+1;
}
//散发
MPI_Scatter(sendbuf,recvnum,MPI_INT,recvArray,recvnum,MPI_INT,root,MPI_COMM_WORLD);
if(rank == root)
{
fprintf(stderr,"\nRoot Process %d, Scattered %d data:",rank,sendnum);
for(i=0;i<sendnum;i++)
fprintf(stderr,"%d,",sendbuf[i]);
fprintf(stderr,"\n");
free(sendbuf); //释放内存
}
MPI_Barrier(MPI_COMM_WORLD); //同步
fprintf(stderr,"\nProcess %d receive %d data:",rank,recvnum);
for(i=0;i<recvnum;i++)
fprintf(stderr,"%d,",recvArray[i]);
fprintf(stderr,"\n");
MPI_Finalize();
}
运行结果
[root@dl1 mpi]# mpirun -np 4 ./test-13-4-1
Root Process 0, Scattered 40 data:6,5,4,4,1,7,7,4,7,3,9,5,1,7,4,2,8,3,3,6,5,4,5,7,8,4,5,9,1,2,4,6,4,7,9,2,4,5,3,8,
Process 0 receive 10 data:6,5,4,4,1,7,7,4,7,3,
Process 1 receive 10 data:9,5,1,7,4,2,8,3,3,6,
Process 2 receive 10 data:5,4,5,7,8,4,5,9,1,2,
Process 3 receive 10 data:4,6,4,7,9,2,4,5,3,8,
int MPI_Scatterv ( void *sendbuf, int *sendcounts, int *displs, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm)