▶ 函数 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()的更多相关文章

  1. MPI 集合通信函数 MPI_Reduce(),MPI_Allreduce(),MPI_Bcast(),MPI_Scatter(),MPI_Gather(),MPI_Allgather(),MPI_Scan(),MPI_Reduce_Scatter()

    ▶ 八个常用的集合通信函数 ▶ 规约函数 MPI_Reduce(),将通信子内各进程的同一个变量参与规约计算,并向指定的进程输出计算结果 ● 函数原型 MPI_METHOD MPI_Reduce( _ ...

  2. MPI 并行奇偶交换排序 + 集合通信函数 Sendrecv() Sendvecv_replace()

    ▶ <并行程序设计导论>第三章的例子程序 ● 代码 #include <stdio.h> #include <mpi.h> #include <stdlib. ...

  3. oracle之集合操作函数---minus、union、intersect

    集合操作符专门用于合并多条select语句的结果,包括:UNION,UNION ALL,INTERSECT,MINUS.当使用集合操作函数时,需保证数据集的字段数据类型和数目一致. 使用集合操作符需要 ...

  4. (Python)集合、集合的函数

    本节我们将学习python的另一种数据类型:集合(set) 1.集合(set) 集合在Python中是一种没有重复元素,且无序的数据类型,且不能通过索引来引用集合中的元素 >>> b ...

  5. 文成小盆友python-num3 集合,函数,-- 部分内置函数

    本接主要内容: set -- 集合数据类型 函数 自定义函数 部分内置函数 一.set 集合数据类型 set集合,是一个无序且不重复的元素集合 集合基本特性 无序 不重复 创建集合 #!/bin/en ...

  6. Oracle集合操作函数:union、intersect、minus

    [转]Oracle集合操作函数:union.intersect.minus 集合操作符专门用于合并多条select 语句的结果,包括:UNION, UNION ALL, INTERSECT, MINU ...

  7. redis 有序集合(zset)函数

    redis 有序集合(zset)函数 zAdd 命令/方法/函数 Adds the specified member with a given score to the sorted set stor ...

  8. mongo的runCommand与集合操作函数的关系

    除了特殊注释外,本文的测试结果均基于 spring-data-mongodb:1.10.6.RELEASE(spring-boot-starter:1.5.6.RELEASE),MongoDB 3.0 ...

  9. linux i2c 的通信函数i2c_transfer在什么情况下出现错误

    问题: linux i2c 的通信函数i2c_transfer在什么情况下出现错误描述: linux i2c设备驱动 本人在写i2c设备驱动的时候使用i2c transfer函数进行通信的时候无法进行 ...

随机推荐

  1. 实时更新数据,无需刷新:a,如何使用Turbolinks clearCache(), b Action Cable

    视频: https://gorails.com/episodes/how-to-use-turbolinks-clearCache?autoplay=1 用途: 更方便的实时从服务器更新局部网页,在这 ...

  2. C# DataTable Compute方法的使用

    在开发中需要对DataTable的数据进行处理,比如累加,求最大最小及平均值等,以前都采用手工对DataTable进行循环并计算的方式,现在发现DataTable的Compute方法可以轻松实现这些功 ...

  3. ssh 上传文件以及文件夹到linux服务器

    闲来无事分享一篇,帮助到你的话,麻烦给老弟点个关注.经常会分享一些实用技能. 回归正题,现在服务器linux很多.是不是不会传文件?别急 下面就是方法: 一.上传文件到linux服务器 首先从你本地切 ...

  4. UVA-1343 The Rotation Game (IDA*)

    题目大意:数字1,2,3都有八个,求出最少的旋转次数使得图形中间八个数相同.旋转规则:对于每一长行或每一长列,每次旋转就是将数据向头的位置移动一位,头上的数放置到尾部.若次数相同,则找出字典序最小旋转 ...

  5. PHP和JAVA整合开发的三个方案(六)

    php作为前端开发,java负责后台开发,这样取长补短的方案很适合现在web开发.现在PHP和JAVA整合开发比较好的方案只有3个:1.SOAP2.php-java-bridge3.Quercus Q ...

  6. 用ansible剧本搭建lnmp

    首先在主服务器上搭建ansible直接用云yum装就可以, yum -y install ansible 如果copy报错一下的语句 "msg": "Aborting, ...

  7. vue.js-读取/发送数据

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. 解决MySQL workbench的Can't connect to MySQL server on '127.0.0.1'(10061)问题

    如题,今天打开MySQL时,出现了这种问题,无法连接到数据库 问题原因:The error (2003) Can't connect to MySQL server on 'server' (1006 ...

  9. Alone

    ---恢复内容开始--- 出处:皮皮bloghttp://blog.csdn.net/pipisorry/article/details/50709014 coding.net: 国内较好的代码托管平 ...

  10. (转)List<T>的各种排序方法

    近日,在工作的时候遇到要对一个大的List<T>集合进行排序,于是就了解下各种List<T>的排序方法. 首先,排序自然就会想到用Sort方法,看看List<T>的 ...