MPI 集合通信函数 MPI_Scatterv(),MPI_Gatherv(),MPI_Allgatherv(),MPI_Alltoall(),MPI_Alltoallv(),MPI_Alltoallw()
▶ 函数 MPI_Scatterv() 和 MPI_Gatherv() 。注意到函数 MPI_Scatter() 和 MPI_Gather() 只能向每个进程发送或接受相同个数的元素,如果希望各进程获得或发送的元素个数不等,就需要时个用着两个函数,不同点是将发送或接受的元素个数变成一个元素个数表和一个元素偏移表,分别指定每个进程的接受或发送状况。
● 函数原型
_Pre_satisfies_(sendbuf != MPI_IN_PLACE) MPI_METHOD MPI_Scatterv(
_In_opt_ const void* sendbuf, // 指向发送数据的指针
_In_opt_ const int sendcounts[], // 发送给各进程数据的个数表
_In_opt_ const int displs[], // 发送给各进程数据关于 sendbuf 的偏移表,注意当 sendcounts[] 不全为 1 时 displs 是以
_In_ MPI_Datatype sendtype, // 发送数据类型
_When_(root != MPI_PROC_NULL, _Out_opt_) void* recvbuf, // 指向接收数据的指针
_In_range_(>= , ) int recvcount, // 接收数据个数
_In_ MPI_Datatype recvtype, // 接收数据类型
_mpi_coll_rank_(root) int root, // 发送数据源进程号
_In_ MPI_Comm comm // 通信子
); _Pre_satisfies_(recvbuf != MPI_IN_PLACE) MPI_METHOD MPI_Gatherv(
_In_opt_ const void* sendbuf, // 指向发送数据的指针,各进程指针可以不同(自带偏移)
_In_range_(>= , ) int sendcount, // 发送数据个数
_In_ MPI_Datatype sendtype, // 发送数据类型
_When_(root != MPI_PROC_NULL, _Out_opt_) void* recvbuf, // 指向接收数据的指针
_In_opt_ const int recvcounts[], // 接收数据个数表(指定存放个数)
_In_opt_ const int displs[], // 接收数据在 recvbuf 中的偏移表(指定存放地点)
_In_ MPI_Datatype recvtype, // 接收数据类型
_mpi_coll_rank_(root) int root, // 接收数据汇进程号
_In_ MPI_Comm comm // 通信子
);
● 使用范例
 {
     const int localSize = , nProcess = , globalSize = ;
     int globalData[globalSize], localData[localSize], count[nProcess], disp[nProcess];
     int comRank, comSize, i, j;
     MPI_Init(&argc, &argv);
     MPI_Comm_rank(MPI_COMM_WORLD, &comRank);
     MPI_Comm_size(MPI_COMM_WORLD, &comSize);
     if (comRank == )
         for (i = ; i < globalSize; globalData[i] = i, i++);
     for (i = ; i < comSize; count[i] = i + , i++);                                    // 向 0 ~ 7 号进程分别发送 1 ~ 8 个数字
     for (disp[] = , i = ; i < comSize; disp[i] = disp[i - ] + count[i - ], i++);   // 每个进程取得的元素的起始地址
     MPI_Scatterv(globalData, count, disp, MPI_INT, localData, count[comRank], MPI_INT, , MPI_COMM_WORLD);  // 分发数据
     for (i = ; i < count[comRank]; i++)                                                // 每个进程将收到的数字加上自身的进程编号
         localData[i] += comRank;
     MPI_Gatherv(localData, count[comRank], MPI_INT, globalData, count, disp, MPI_INT, , MPI_COMM_WORLD);   // 聚集数据
     if (comRank == )                                                                   // 输出结果
     {
         for (i = ; i < globalSize; i++)
             printf("%d ", globalData[i]);
     }
     MPI_Finalize();
     return ;
 }
● 输出结果:
D:\Code\MPI\MPIProjectTemp\x64\Debug>mpiexec -n -l MPIProjectTemp.exe
[]
// 即 0+0,1+1,2+1,3+2,4+2,5+2,6+3,7+3,8+3,9+3,……,35+7
▶ 函数 MPI_Allgatherv() ,同时具备 MPI_Allgather() 和 MPI_Gatherv() 的特点,即各进程各自拥有同一向量中长度不相等的各分段,要将他们全部同步为整个向量
● 函数原型,仅比函数 MPI_Gatherv() 少了一个 root 参数
_Pre_satisfies_(recvbuf != MPI_IN_PLACE) MPI_METHOD MPI_Allgatherv(
_In_opt_ const void* sendbuf, // 指向发送数据的指针
_In_range_(>= , ) int sendcount, // 发送数据量
_In_ MPI_Datatype sendtype, // 发送数据类型
_Out_opt_ void* recvbuf, // 指向接收数据的指针
_In_ const int recvcounts[], // 从各进程接收的数据量
_In_ const int displs[], // 从各进程接收的数据在 recvbuf 中的偏移
_In_ MPI_Datatype recvtype, // 接收数据类型
_In_ MPI_Comm comm // 通信子
);
● 使用范例
int main(int argc, char **argv)
{
const int localSize = , nProcess = , globalSize = ;
int globalData[globalSize], localData[localSize], count[nProcess], disp[nProcess];
int comRank, comSize, i; MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &comRank);
MPI_Comm_size(MPI_COMM_WORLD, &comSize); if (comRank == ) // 0 号进程初始化为所需数据,其他进程初始化为 -1
for (i = ; i < globalSize; globalData[i] = i, i++);
else
for (i = ; i < globalSize; globalData[i] = , i++);
for (i = ; i < localSize; localData[i++] = -);
for (i = ; i < comSize; count[i] = i + , i++);
for (disp[] = , i = ; i < comSize; disp[i] = disp[i - ] + count[i - ], i++); MPI_Scatterv(globalData, count, disp, MPI_INT, localData, count[comRank], MPI_INT, , MPI_COMM_WORLD); // 分发数据
for (i = ; i < count[comRank]; i++)
localData[i] += comRank;
MPI_Allgatherv(localData, count[comRank], MPI_INT, globalData, count, disp, MPI_INT, MPI_COMM_WORLD); // 聚集数据 for (i = ; i < globalSize; i++)
printf("%d ", globalData[i]); MPI_Finalize();
return ;
}
● 输出结果
D:\Code\MPI\MPIProjectTemp\x64\Debug>mpiexec -n -l MPIProjectTemp.exe
[]
[]
[]
[]
[]
[]
[]
[]
▶ 函数 MPI_Alltoall(),MPI_Alltoallv(),MPI_Alltoallw() 。类似函数 MPI_Allgather() 的扩展,从每个进程的数据中挑出一部分来对所有的进程进行同步,第一个函数要求相同的大小和数据类型,第二个函数可以不同大小,第三个函数可以不同的数据类型
● 函数原型
_Pre_satisfies_(recvbuf != MPI_IN_PLACE) MPI_METHOD MPI_Alltoall(
_In_opt_ _When_(sendtype == recvtype, _In_range_(!= , recvbuf)) const void* sendbuf,// 指向发送数据的指针
_In_range_(>= , ) int sendcount, // 发送数据个数
_In_ MPI_Datatype sendtype, // 发送数据类型
_Out_opt_ void* recvbuf, // 指向接收数据的指针
_In_range_(>= , ) int recvcount, // 接收数据个数
_In_ MPI_Datatype recvtype, // 接收数据类型
_In_ MPI_Comm comm // 通信子
); _Pre_satisfies_(recvbuf != MPI_IN_PLACE) MPI_METHOD MPI_Alltoallv(
_In_opt_ const void* sendbuf, // 指向发送数据的指针
_In_opt_ const int sendcounts[], // 发送数据个数列表
_In_opt_ const int sdispls[], // 发送数据的偏移列表
_In_ MPI_Datatype sendtype, // 发送数据类型
_Out_opt_ void* recvbuf, // 指向接收数据的指针
_In_ const int recvcounts[], // 接收数据个数列表
_In_ const int rdispls[], // 接收数据的偏移列表
_In_ MPI_Datatype recvtype, // 接收数据类型
_In_ MPI_Comm comm // 通信子
); _Pre_satisfies_(recvbuf != MPI_IN_PLACE) MPI_METHOD MPI_Alltoallw(
_In_opt_ const void* sendbuf, // 指向发送数据的指针
_In_opt_ const int sendcounts[], // 发送数据列表
_In_opt_ const int sdispls[], // 发送数据的偏移列表
_In_opt_ const MPI_Datatype sendtypes[], // 发送数据的类型列表
_Out_opt_ void* recvbuf, // 指向接收数据的指针
_In_ const int recvcounts[], // 接收数据个数列表
_In_ const int rdispls[], // 接收数据的偏移列表
_In_ const MPI_Datatype recvtypes[], // 接收数据类型列表
_In_ MPI_Comm comm // 通信子
);
● 函数 MPI_Alltoall() 使用范例
 {
     const int localSize = , nProcess = , globalSize = localSize * nProcess;
     int comRank, comSize, i, sendData[globalSize], receiveData[globalSize];
     MPI_Init(&argc, &argv);
     MPI_Comm_rank(MPI_COMM_WORLD, &comRank);
     MPI_Comm_size(MPI_COMM_WORLD, &comSize);
     for (i = ; i < globalSize; sendData[i] = comRank + , receiveData[i] = , i++);
     MPI_Alltoall(sendData, localSize, MPI_INT, receiveData, localSize, MPI_INT, MPI_COMM_WORLD);
     for (i = ; i < globalSize; i++)
         printf("%d, ", sendData[i]);
     fflush(stdout), MPI_Barrier(MPI_COMM_WORLD);// 使用缓冲区清空函数 fflush() 和同步函数 MPI_Barrier() 来实现分隔输出
     for (i = ; i < globalSize; i++)
         printf("%d, ", receiveData[i]);
     MPI_Finalize();
     return ;
 }
● 输出结果,前 8 行为原始数据,同一个进程内所有元素均相等;后 8 行为通信后的数据,所有的进程数据都相同,各分段的值来自不同的进程
D:\Code\MPI\MPIProjectTemp\x64\Debug>mpiexec -n -l MPIProjectTemp.exe
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
● 函数 MPI_Alltoallv() 使用范例
 {
     const int nProcess = ;
     int sendData[nProcess * nProcess], receiveData[nProcess * nProcess];
     int sendCount[nProcess], receiveCount[nProcess], sendDisp[nProcess], receiveDisp[nProcess];
     int comRank, comSize, i;
     MPI_Init(&argc, &argv);
     MPI_Comm_size(MPI_COMM_WORLD, &comSize);
     MPI_Comm_rank(MPI_COMM_WORLD, &comRank);    
     for (i = ; i < comSize * comSize; sendData[i] =  * comRank + i, receiveData[i] = -, i++);
     for (i = ; i < comSize; i++)
     {
         sendCount[i] = i;
         receiveCount[i] = comRank;
         receiveDisp[i] = i * comRank;
         sendDisp[i] = (i * (i + )) / ;
     }
     MPI_Alltoallv(sendData, sendCount, sendDisp, MPI_INT, receiveData, receiveCount, receiveDisp, MPI_INT, MPI_COMM_WORLD);
     for (i = ; i < comSize * comSize; i++)
         printf("%3d ", sendData[i]);
     fflush(stdout), MPI_Barrier(MPI_COMM_WORLD);
     for (i = ; i < comSize * comSize; i++)
         printf("%3d ", receiveData[i]);
     /*// 二维形式打印 sendData 和 receiveData
     for (i = 0; i < comSize; i++)
     {
         for (int j = 0; j < comSize; j++)
             printf("%3d ", sendData[i*comSize + j]);
         printf("\n");
     }
     fflush(stdout), MPI_Barrier(MPI_COMM_WORLD);
     for (i = 0; i < comSize; i++)
     {
         for (int j = 0; j < comSize; j++)
             printf("%3d ", receiveData[i*comSize + j]);
         printf("\n");
     }
     */
     MPI_Finalize();
     return ;
 }
● 输出结果
D:\Code\MPI\MPIProjectTemp\x64\Debug>mpiexec -n -l MPIProjectTemp.exe
[]
[]
[]
[]
[]
[]
[]
[]
[] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[] - - - - - - - - - - - - - - - - - - - - - - - -
[] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[] - - - - - - - - - - - - - - - -
[] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[] - - - - - - - -
[] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
● 函数 MPI_Alltoallw() 使用范例(从函数 MPI_Alltoallv() 范例改过来的)
 {
     const int nProcess = ;
     int sendData[nProcess * nProcess], receiveData[nProcess * nProcess];
     int sendCount[nProcess], receiveCount[nProcess], sendDisp[nProcess], receiveDisp[nProcess];
     MPI_Datatype dataType[nProcess];
     int comRank, comSize, i;
     MPI_Init(&argc, &argv);
     MPI_Comm_size(MPI_COMM_WORLD, &comSize);
     MPI_Comm_rank(MPI_COMM_WORLD, &comRank);    
     for (i = ; i < comSize * comSize; sendData[i] =  * comRank + i, receiveData[i] = -, i++);
     for (i = ; i < comSize; i++)
     {
         sendCount[i] = i;
         receiveCount[i] = comRank;
         receiveDisp[i] = i * comRank * sizeof(int);   // 因为数据类型放宽,偏移地址改用字节为单位
         sendDisp[i] = (i * (i + )) /  * sizeof(int);
         dataType[i] = MPI_INT;                        // 数据类型从单变成为列表
     }
     MPI_Alltoallw(sendData, sendCount, sendDisp, dataType, receiveData, receiveCount, receiveDisp, dataType, MPI_COMM_WORLD);// 把两个数据类型的参数换成列表
     for (i = ; i < comSize * comSize; i++)
         printf("%3d ", sendData[i]);
     fflush(stdout), MPI_Barrier(MPI_COMM_WORLD);
     for (i = ; i < comSize * comSize; i++)
         printf("%3d ", receiveData[i]);
     /*// 二维形式打印 sendData 和 receiveData
     for (i = 0; i < comSize; i++)
     {
         for (int j = 0; j < comSize; j++)
             printf("%3d ", sendData[i*comSize + j]);
         printf("\n");
     }
     fflush(stdout), MPI_Barrier(MPI_COMM_WORLD);
     for (i = 0; i < comSize; i++)
     {
         for (int j = 0; j < comSize; j++)
             printf("%3d ", receiveData[i*comSize + j]);
         printf("\n");
     }
     */
     MPI_Finalize();
     return ;
 }
● 输出结果同函数 MPI_Alltoallv() 的范例
MPI 集合通信函数 MPI_Scatterv(),MPI_Gatherv(),MPI_Allgatherv(),MPI_Alltoall(),MPI_Alltoallv(),MPI_Alltoallw()的更多相关文章
- MPI 集合通信函数 MPI_Reduce(),MPI_Allreduce(),MPI_Bcast(),MPI_Scatter(),MPI_Gather(),MPI_Allgather(),MPI_Scan(),MPI_Reduce_Scatter()
		
▶ 八个常用的集合通信函数 ▶ 规约函数 MPI_Reduce(),将通信子内各进程的同一个变量参与规约计算,并向指定的进程输出计算结果 ● 函数原型 MPI_METHOD MPI_Reduce( _ ...
 - MPI 并行奇偶交换排序 + 集合通信函数 Sendrecv() Sendvecv_replace()
		
▶ <并行程序设计导论>第三章的例子程序 ● 代码 #include <stdio.h> #include <mpi.h> #include <stdlib. ...
 - oracle之集合操作函数---minus、union、intersect
		
集合操作符专门用于合并多条select语句的结果,包括:UNION,UNION ALL,INTERSECT,MINUS.当使用集合操作函数时,需保证数据集的字段数据类型和数目一致. 使用集合操作符需要 ...
 - (Python)集合、集合的函数
		
本节我们将学习python的另一种数据类型:集合(set) 1.集合(set) 集合在Python中是一种没有重复元素,且无序的数据类型,且不能通过索引来引用集合中的元素 >>> b ...
 - 文成小盆友python-num3 集合,函数,-- 部分内置函数
		
本接主要内容: set -- 集合数据类型 函数 自定义函数 部分内置函数 一.set 集合数据类型 set集合,是一个无序且不重复的元素集合 集合基本特性 无序 不重复 创建集合 #!/bin/en ...
 - Oracle集合操作函数:union、intersect、minus
		
[转]Oracle集合操作函数:union.intersect.minus 集合操作符专门用于合并多条select 语句的结果,包括:UNION, UNION ALL, INTERSECT, MINU ...
 - redis 有序集合(zset)函数
		
redis 有序集合(zset)函数 zAdd 命令/方法/函数 Adds the specified member with a given score to the sorted set stor ...
 - mongo的runCommand与集合操作函数的关系
		
除了特殊注释外,本文的测试结果均基于 spring-data-mongodb:1.10.6.RELEASE(spring-boot-starter:1.5.6.RELEASE),MongoDB 3.0 ...
 - linux i2c 的通信函数i2c_transfer在什么情况下出现错误
		
问题: linux i2c 的通信函数i2c_transfer在什么情况下出现错误描述: linux i2c设备驱动 本人在写i2c设备驱动的时候使用i2c transfer函数进行通信的时候无法进行 ...
 
随机推荐
- Java 集合-Map接口和三个子类实现
			
2017-10-31 22:05:59 Map 将键映射到值的对象.一个映射不能包含重复的键:每个键最多只能映射到一个值. HashMap是基于散列表实现的,插入.删除和定位元素时间复杂度平均能达到O ...
 - OOP的感悟
			
不要认为你关心的东西就是对象的全部或对象的核心,相对于对象的成员家族而言,它仅仅是其中的一个‘很小的成员而已’
 - 个人知识管理系统Version1.0开发记录(10)
			
物理分页 这次我们运用Mybatis拦截器来实现物理分页,后面会运用动态sql来实现,或者运用Map/CollectionUtils/StringUtils编写工具类来实现.oracle是运用的row ...
 - asp.net中的时间日期选择控件
			
asp.net中的时间日期选择控件 Posted on 2008-07-17 17:37 飛雪飄寒 阅读(22922) 评论(6) 编辑 收藏 在系统中经常需要进行时间日期选择(比如查询时间范 ...
 - 更新.xsd后,rdlc 数据源更新不了
 - 趣谈StateServer在Web Garden,Web Farm下的使用
			
上一篇翻译的博客[译文]漫谈ASP.NET中的Session已经介绍了Session的基础知识,如果看过了的话对Session应该有了一个比较清晰的认识了,现在我来谈谈我所遇到的困境以及对Sessio ...
 - Alpha冲刺一(7/10)
			
前言 队名:拖鞋旅游队 组长博客:https://www.cnblogs.com/Sulumer/p/10013652.html 作业博客:https://edu.cnblogs.com/campus ...
 - linux内存查看工具
			
这里帮你总结了一下Linux下查看内存使用情况的多种方法~ 在做 Linux 系统优化的时候,物理内存是其中最重要的一方面.自然的,Linux 也提供了非常多的方法来监控宝贵的内存资源的使用情况.下面 ...
 - CS231n课程笔记翻译9:卷积神经网络笔记
			
译者注:本文翻译自斯坦福CS231n课程笔记ConvNet notes,由课程教师Andrej Karpathy授权进行翻译.本篇教程由杜客和猴子翻译完成,堃堃和李艺颖进行校对修改. 原文如下 内容列 ...
 - webpack 提升90%的构建速度 HardSourceWebpackPlugin
			
HardSourceWebpackPlugin 插件 不能提升第一次构建的速度,但对于第二次构建能提升99%的构建速度 第一次构建: 第二次: 提升了..,算不出来,反正就是很多啦~~~ npm in ...