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函数进行通信的时候无法进行 ...
随机推荐
- 遗传算法 Genetic Algorithm
2017-12-17 19:12:10 一.Evolutionary Algorithm 进化算法,也被成为是演化算法(evolutionary algorithms,简称EAs),它不是一个具体的算 ...
- JS中constructor与prototype关系概论
在学习JS的面向对象过程中,一直对constructor与prototype感到很迷惑,看了一些博客与书籍,觉得自己弄明白了,现在记录如下: 我们都知道,在JS中有一个function的东西. ...
- day40 数据结构-算法(二)
什么是数据结构? 简单来说,数据结构就是设计数据以何种方式组织并存储在计算机中. 比如:列表.集合与字典等都是一种数据结构. N.Wirth: “程序=数据结构+算法” 列表 列表:在其他编程语言中称 ...
- Reverse engineer powerdesigner link odbc
Reverse engineer powerdesigner link odbc Option Explicit ValidationMode = True Interactive ...
- windows下jenkins安装过程中的那些坑
在jenkins官网https://jenkins.io/download/下载2.89.4版本的war包,使用jar -jar jenkins.war命令安装,报端口被占的错误,使用jar -jar ...
- New Concept English Two 8 19
pls practice every day $课文17 青春常驻 161. My aunt Jennifer is an actress. 我的姑姑詹妮弗是位演员, 162. She must b ...
- vue.js 源代码学习笔记 ----- helpers.js
/* @flow */ import { parseFilters } from './parser/filter-parser' export function baseWarn (msg: str ...
- Centos7 安装JDK环境和Tomcat
Linux JDK 64位下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk9-downloads-3848520.ht ...
- iOS-----MFMessageCompose 和 MFMailComposeViewController的使用方法
MFMessageCompose 和 MFMailComposeViewController的使用方法 使用MFMessageComposeViewCOntroller发短信 应用想自己提供界面让用户 ...
- 這是我既C語言作業寫博客後寫的第一篇博客
這篇博客應該算是寫給我自己的博客吧,所以這裏我想用繁體字寫,因為我漸漸地發現我已經很少使用到繁體字了,日常QQ聊天都使用簡體字,繁體字都懶得切換了,但是為了不讓別人麻煩,在外界交流的時候我會使用簡體字 ...