MPI:每天的集合通信 |
集合通信意味着一个通信子中的所有进程调用同一例程。可移植的应用应该假定集合例程包含全局的同步。
下面简单的代码段使用了四个基本的集合例程以操纵一个静态的已划分的规则区域(这里是一维)。全域的长度从根进程广播到所有其它进程。初始数据集在进程间分配(分散)。在每一计算步骤之后,确定全局的最大数并由根所使用。根然后收集最终的数据集。
#include <mpi.h>
{
int i;
int myrank;
int size;
int root;
int full_domain_length;
int sub_domain_length;
double global_max;
double local_max;
double *full_domain;
double *sub_domain;
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
root = 0;
/*
* 根包含全居域并且广播它的长度。
*/
if (myrank == root) {
get_full_domain(&full_domain, &full_domain_length);
}
MPI_Bcast(&full_domain_length, 1, MPI_INT, root, MPI_COMM_WORLD);
/*
* 分配子域内存。
* 在进程间分散初始数据集
*/
sub_domain_length = full_domain_length / size;
sub_domain = (double *) malloc(sub_domain_length * sizeof(double));
MPI_Scatter(full_domain, sub_domain_length, MPI_DOUBLE,
sub_domain, sub_domain_length, MPI_DOUBLE,
root, MPI_COMM_WORLD);
/*
* 循环计算和确定最大数。
*/
for (i = 0; i < NSTEPS; ++i) {
compute(sub_domain, sub_domain_length, &local_max);
MPI_Reduce(&local_max, &global_max, 1, MPI_DOUBLE,
MPI_MAX, root, MPI_COMM_WORLD);
}
/*
* 收集最终数据集
*/
MPI_Gather(sub_domain, sub_domain_length, MPI_DOUBLE,
full_domain, sub_domain_length, MPI_DOUBLE,
root, MPI_COMM_WORLD);
}
MPI_Bcast(void *buffer, int count, MPI_Datatype datatype,
int root, MPI_Comm comm);
所有进程使用同一计数、数据类型、根和通信子。在操作前,根缓冲区包含一个消息。操作后,所有缓冲区包含来自根进程的消息。
MPI_Scatter(void *sndbuf, int sndcnt, MPI_Datatype sndtype,
void *rcvbuf, int rcvcnt, MPI_Datatype rcvtype,
int root, MPI_Comm comm);
所有进程使用同一计数、数据类型、根和通信子。在操作前,根发送缓冲区包含长度为`sndcnt * N'的消息,这里N是进程数目。操作后,相等地划分消息,并且分散到随后标识数序的所有进程(包括根)。
MPI_Reduce(void *sndbuf, void *rcvbuf, int count,
MPI_Datatype datatype, MPI_Op op,
int root, MPI_Comm comm);
所有进程使用同一计数、数据类型、根和通信子。操作后,根进程在它的接受缓冲区中有所有进程的发送缓冲区的归约结果,包括:MPI_MAX, MPI_MIN, MPI_SUM, MPI_PROD, MPI_LAND, MPI_BAND, MPI_LOR, MPI_BOR, MPI_LXOR, MPI_BXOR。
MPI_Gather(void *sndbuf, int sndcnt, MPI_Datatype sndtype,
void *rcvbuf, int rcvcnt, MPI_Datatype rcvtype,
int root, MPI_Comm comm);
所有进程使用同一计数、数据类型、根和通信子。此例程是MPI_Scatter()的相反:操作后,根进程在它的接受缓冲区中包含所有进程的发送缓冲区的连接(包括它自己),所有消息长度为`rcvcnt * N', 这里N是进程数目。按照随后的标识数序收集消息。
| Copyright: NPACT |