▶ 函数 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. YAML(摘录)

    YAML:维基百科 一个用来表达数据序列的格式.强调以数据为中心的标记语言. 使用空白符缩进和大量依赖外观的特殊,适合编辑数据结构,配置文件. 基本格式: 缩进/区块 和内置两者格式,来表示array ...

  2. 个人知识管理系统Version1.0开发记录(07)

    模 块 复 用 原本还要测试一会的,突然出现一连串诡异的问题,比如,编译少加载个类啊,输入地址少个字母啊,改几行代码一改就是半小时啊.这是在提醒我们大脑疲倦了,所以果断小结,下次继续.这一次简单完成了 ...

  3. Unsupported major.minor version 51.0解决办法(转)

    我使用的是Eclipse-jee-indigo + JDK 1.6.23环境,结果使用时出现Unsupported major.minor version 51.0错误提示,下面我来介绍Unsuppo ...

  4. vue router动态路由

    <div id="#app"> <router-link to="/user/header">路由1</router-link&g ...

  5. 保卫萝卜官方PC版——含绿色版 V1.0.6Beta

    官方网站 | 安装版 | 绿色版

  6. java 注解总结

    @Controller用于标注控制层组件 @Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象.分发处理器将会扫描使用了该注解的类的方法.通 ...

  7. I.MX6 Linux 3.0.35 SD boot

    /********************************************************************************* * I.MX6 Linux 3.0 ...

  8. streamsets 错误记录处理

    我们可以在stage 级别,或者piepline 级别进行error 处理配置 pipeline的错误记录处理 discard(丢踢) send response to Origin pipeline ...

  9. Maven管理SSM框架的pom.xml文件配置(自己主动下载所依赖的jar包)

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/UP19910522/article/details/25403855 <project xml ...

  10. C#多线程应用:子线程更新主窗体控件的值(一)

    我记得以前写过一次关于多线程的调用及更新的文章,由于时间比较久了,现在一时没找到.在做项目的时候,用到了多线程,还是有很多的同事在问多线程更新主窗体的事情,现在就这个事情做个记录. 说起多线程之间的更 ...