MPI Note[4]: 集合通信
•
文章
前面讲完了点到点通信,下面来看另一个话题,集体(Collective)通信. 点到点的时候已经介绍了一些关于MPI_Barrier的内容:
接下来介绍一些BCast、Scatter、Gather的操作
MPI_Bcast
半开玩笑的说,应该叫组播更合适,因为MPI_Bcast有明确的MPI_Comm
组,和组播源root
的概念
MPI_Bcast(void* data, int count, MPI_Datatype datatype, int root, MPI_Comm communicator)
这种模式用于将相同的数据分发到其它节点,如下图所示:
当然一开始,我们就可以用单播的方式,一个个的发就好
void my_bcast(void* data, int count, MPI_Datatype datatype, int root, MPI_Comm communicator) {
int world_rank;
int world_size;
MPI_Comm_rank(communicator, &world_rank);
MPI_Comm_size(communicator, &world_size);
if (world_rank == root) {
//作为根节点逐个单播发送
int i;
for (i = 0; i < world_size; i++) {
if (i != world_rank) {
MPI_Send(data, count, datatype, i, 0, communicator);
}
}
} else {
//其它节点阻塞接收
MPI_Recv(data, count, datatype, root, 0, communicator, MPI_STATUS_IGNORE);
}
}
但是系统自带的更加高效的一种树状分发结构:
但是这样的分发效率并不是很高,初期泛洪速度有些慢,而思科ASR1000组播也是类似的,只是一开始就复制N份出去,第二轮N*N…N是几不能说
// Author: Wes Kendall
// Copyright 2011 www.mpitutorial.com
// This code is provided freely with the tutorials on mpitutorial.com. Feel
// free to modify it for your own use. Any distribution of the code must
// either provide a link to www.mpitutorial.com or keep this header intact.
//
// Comparison of MPI_Bcast with the my_bcast function
//
MPI_Scatter
MPI_Scatter 和MPI_Bcast的不同点在于,Scatter针对每个非root节点分发的数据都不同。
MPI_Scatter(
void* send_data,
int send_count,
MPI_Datatype send_datatype,
void* recv_data,
int recv_count,
MPI_Datatype recv_datatype,
int root,
MPI_Comm communicator)具体实例如下,首先我们在Root节点构造了一个array,然后每个node构造了用于接受的sub_array,并且在MPI_Scatter中定义好了发送和接收的数量。
执行
zartbot@mpi1:~/mpi/study/collective$ mpicc scatter.c -o scatter
zartbot@mpi1:~/mpi/study/collective$ mpiexec -np 8 ./scatter 2
proc 0 sub_array[0]: 0.000000
proc 0 sub_array[1]: 1.000000
proc 1 sub_array[0]: 2.000000
proc 1 sub_array[1]: 3.000000
proc 2 sub_array[0]: 4.000000
proc 2 sub_array[1]: 5.000000
proc 3 sub_array[0]: 6.000000
proc 3 sub_array[1]: 7.000000
proc 4 sub_array[0]: 8.000000
proc 4 sub_array[1]: 9.000000
proc 5 sub_array[0]: 10.000000
proc 5 sub_array[1]: 11.000000
proc 6 sub_array[0]: 12.000000
proc 6 sub_array[1]: 13.000000
proc 7 sub_array[0]: 14.000000
proc 7 sub_array[1]: 15.000000
zartbot@mpi1:~/mpi/study/collective$ mpiexec -np 8 ./scatter 3
proc 0 sub_array[0]: 0.000000
proc 0 sub_array[1]: 1.000000
proc 0 sub_array[2]: 2.000000
proc 1 sub_array[0]: 3.000000
proc 1 sub_array[1]: 4.000000
proc 1 sub_array[2]: 5.000000
proc 2 sub_array[0]: 6.000000
proc 2 sub_array[1]: 7.000000
proc 2 sub_array[2]: 8.000000
proc 3 sub_array[0]: 9.000000
proc 3 sub_array[1]: 10.000000
proc 3 sub_array[2]: 11.000000
proc 4 sub_array[0]: 12.000000
proc 4 sub_array[1]: 13.000000
proc 4 sub_array[2]: 14.000000
proc 5 sub_array[0]: 15.000000
proc 5 sub_array[1]: 16.000000
proc 5 sub_array[2]: 17.000000
proc 6 sub_array[0]: 18.000000
proc 6 sub_array[1]: 19.000000
proc 6 sub_array[2]: 20.000000
proc 7 sub_array[0]: 21.000000
proc 7 sub_array[1]: 22.000000
proc 7 sub_array[2]: 23.000000MPI_Gather
Gather和Scatter刚好相反,如下图所示:
MPI_Gather(
void* send_data,
int send_count,
MPI_Datatype send_datatype,
void* recv_data,
int recv_count,
MPI_Datatype recv_datatype,
int root,
MPI_Comm communicator)例如我们来做一个示例
执行:
zartbot@mpi1:~/mpi/study/collective$ mpicc gather.c -o gather
zartbot@mpi1:~/mpi/study/collective$ mpiexec -np 8 ./gather 3
all_array[0]: 0.000000
all_array[1]: 0.000000
all_array[2]: 0.000000
all_array[3]: 1.000000
all_array[4]: 1.000000
all_array[5]: 1.000000
all_array[6]: 2.000000
all_array[7]: 2.000000
all_array[8]: 2.000000
all_array[9]: 3.000000
all_array[10]: 3.000000
all_array[11]: 3.000000
all_array[12]: 4.000000
all_array[13]: 4.000000
all_array[14]: 4.000000
all_array[15]: 5.000000
all_array[16]: 5.000000
all_array[17]: 5.000000
all_array[18]: 6.000000
all_array[19]: 6.000000
all_array[20]: 6.000000
all_array[21]: 7.000000
all_array[22]: 7.000000
all_array[23]: 7.000000一个计算平均数的示例
zartbot@mpi1:~/mpi/study/collective$ mpicc avg.c -o avg
zartbot@mpi1:~/mpi/study/collective$ mpiexec -np 8 ./avg 3
proc 0 sub_array[0]: 0.000000
proc 0 sub_array[1]: 1.000000
proc 0 sub_array[2]: 2.000000
proc 1 sub_array[0]: 3.000000
proc 1 sub_array[1]: 4.000000
proc 1 sub_array[2]: 5.000000
proc 2 sub_array[0]: 6.000000
proc 2 sub_array[1]: 7.000000
proc 2 sub_array[2]: 8.000000
proc 3 sub_array[0]: 9.000000
proc 3 sub_array[1]: 10.000000
proc 3 sub_array[2]: 11.000000
proc 4 sub_array[0]: 12.000000
proc 4 sub_array[1]: 13.000000
proc 4 sub_array[2]: 14.000000
proc 5 sub_array[0]: 15.000000
proc 5 sub_array[1]: 16.000000
proc 5 sub_array[2]: 17.000000
proc 6 sub_array[0]: 18.000000
proc 6 sub_array[1]: 19.000000
proc 6 sub_array[2]: 20.000000
proc 7 sub_array[0]: 21.000000
proc 7 sub_array[1]: 22.000000
proc 7 sub_array[2]: 23.000000
proc 0 sub_average: 1.000000
proc 1 sub_average: 4.000000
proc 2 sub_average: 7.000000
proc 3 sub_average: 10.000000
proc 4 sub_average: 13.000000
proc 5 sub_average: 16.000000
proc 7 sub_average: 22.000000
proc 6 sub_average: 19.000000
Avg of all elements is 11.500000
zartbot@mpi1:~/mpi/study/collective$MPI_Allgather
等于MPI_Gather后再加一个Bcast
例如我们稍微修改一下前述代码
MPI_Barrier(MPI_COMM_WORLD);
printf("proc %d sub_average: %f\n", world_rank, sub_avg);
float *sub_avgs = (float *)malloc(sizeof(float) * world_size);
MPI_Allgather(&sub_avg, 1, MPI_FLOAT, sub_avgs, 1, MPI_FLOAT, MPI_COMM_WORLD);
float avg = compute_avg(sub_avgs, world_size);
printf("Proc %d Avg of all elements is %f\n", world_rank,avg);
if (world_rank == 0)
{
free(array);
}执行结果
Proc 7 Avg of all elements is 11.500000
Proc 1 Avg of all elements is 11.500000
Proc 4 Avg of all elements is 11.500000
Proc 2 Avg of all elements is 11.500000
Proc 0 Avg of all elements is 11.500000
Proc 5 Avg of all elements is 11.500000
Proc 3 Avg of all elements is 11.500000
Proc 6 Avg of all elements is 11.500000
《MPI Note[4]: 集合通信》来自互联网,仅为收藏学习,如侵权请联系删除。本文URL:http://www.bookhoes.com/744.html