【MPI学习7】MPI并行程序设计模式:MPI的进程组和通信域
基于都志辉老师MPI编程书中的第15章内容。
通信域是MPI的重要概念:MPI的通信在通信域的控制和维护下进行 → 所有MPI通信任务都直接或间接用到通信域这一参数 → 对通信域的重组和划分可以方便实现任务的划分
(1)通信域(communicator)是一个综合的通信概念。其包括上下文(context),进程组(group),虚拟处理器拓扑(topology)。其中进程组是比较重要的概念,表示通信域中所有进程的集合。一个通信域对应一个进程组。
(2)进程(process)与进程组(group)的关系。每个进程是客观上唯一的(一个进程对应一个pid号);同一个进程可以属于多个进程组(每个进程在不同进程组中有个各自的rank号);同一个进程可以属于不同的进程组,因此也可以属于不同的通信域。
(3)通信域产生的方法。根据看过的资料,大概有三种方法,先简要了解路子即可:
a. 在已有通信域基础上划分获得:MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm *newcomm)
b. 在已有通信域基础上复制获得:MPI_Comm_dup(MPI_Comm comm, MPI_Comm *newcomm)
c. 在已有进程组的基础上创建获得:MPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm *newcomm)
(4)进程组产生的方法。进程组(group)可以当成一个集合的概念,可以通过“子、交、并、补”各种方法。所有进程组产生的方法都可以套到集合的各种运算,用到的时候现看函数就可以了。
(5)“当前进程”与“通信域产生函数”。如果在已有进程组的基础上创建新的通信域(即(3)中c方法),则newcomm有两种结果:如果调用MPI_Comm_create的当前进程在group中,则newcomm就是新产生的通信域对象;如果调用MPI_Comm_create的当前进程不在group中,则newcomm就是MPI_COMM_NULL。由于MPI是多进程编程,类似“当前进程”与“通信域产生函数”这种情况会比较频繁的出现,在设计思路上要适应并行编程这种改变。
(6)不同通信域间互不干扰。“互不干扰”严格来说并不完全正确,这里想说的意思是:同一个进程,可以属于不同的通信域;同一个进程可以同时参与不同通信域的通信,互不干扰。
下面通过一个例子来感受一下进程组和通信域在MPI多进程任务划分和处理上的应用。
代码做的事情如下:
(1)共有6个进程,在MPI_COMM_WORLD中的编号分别是{0,1,2,3,4,5}。
(2)将{1,3,5}进程形成一个新的通信域comm1;将编号为{0,2,4}的进程生成一个新的通信域comm2
(3)在comm1中执行MAX归约操作;在comm2中执行MIN归约操作;在MPI_COMM_WORLD中执行SUM归约操作
(4)显示各个通信域中归约操作的结果
具体代码如下:
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h> #define LEN 5 int main(int argc, char *argv[])
{
MPI_Init(&argc, &argv);
int world_rank, world_size;
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
MPI_Comm_rank(MPI_COMM_WORLD, &world_size); MPI_Group world_group;
MPI_Comm_group(MPI_COMM_WORLD, &world_group); int n = ;
const int ranks[] = {,,};
const int ori1[] = {};
const int ori2[] = {};
int root1, root2; // 从world_group进程组中构造出来两个进程组
MPI_Group group1, group2;
MPI_Group_incl(world_group, n, ranks, &group1);
MPI_Group_excl(world_group, n, ranks, &group2);
// 根据group1 group2分别构造两个通信域
MPI_Comm comm1, comm2;
MPI_Comm_create(MPI_COMM_WORLD, group1, &comm1);
MPI_Comm_create(MPI_COMM_WORLD, group2, &comm2); // 维护发送缓冲区和接受缓冲区
int i;
double *sbuf, *rbuf1, *rbuf2, *rbuf3;
sbuf = malloc(LEN*sizeof(double));
rbuf1 = malloc(LEN*sizeof(double));
rbuf2 = malloc(LEN*sizeof(double));
rbuf3 = malloc(LEN*sizeof(double));
srand(world_rank*);
for(i=; i<LEN; i++) sbuf[i] = (1.0*rand()) / RAND_MAX;
fprintf(stderr,"rank %d:\t", world_rank);
for(i=; i<LEN; i++) fprintf(stderr,"%f\t",sbuf[i]);
fprintf(stderr,"\n");
MPI_Group_translate_ranks(world_group, , ori1, group1, &root1);
MPI_Group_translate_ranks(world_group, , ori2, group2, &root2);
// MPI_COMM_WORLD comm1 comm2分别执行不同的归约操作
if (MPI_COMM_NULL!=comm1) { // comm1
MPI_Reduce(sbuf, rbuf1, LEN, MPI_DOUBLE, MPI_MAX, root1, comm1);
int rank_1;
MPI_Comm_rank(comm1, &rank_1);
if (root1==rank_1) {
fprintf(stderr,"MAX:\t");
for(i=; i<LEN; i++) fprintf(stderr,"%f\t",rbuf1[i]);
fprintf(stderr,"\n");
}
}
else if (MPI_COMM_NULL!=comm2) { // comm2
MPI_Reduce(sbuf, rbuf2, LEN, MPI_DOUBLE, MPI_MIN, root2, comm2);
int rank_2;
MPI_Comm_rank(comm2, &rank_2);
if (root2==rank_2) {
fprintf(stderr,"MIN:\t");
for(i=; i<LEN; i++) fprintf(stderr,"%f\t",rbuf2[i]);
fprintf(stderr,"\n");
}
}
MPI_Reduce(sbuf, rbuf3, LEN, MPI_DOUBLE, MPI_SUM, , MPI_COMM_WORLD); // MPI_COMM_WORLD
if (==world_rank) {
fprintf(stderr,"SUM:\t");
for(i=; i<LEN; i++) fprintf(stderr,"%f\t",rbuf3[i]);
fprintf(stderr,"\n");
}
// 清理进程组和通信域
if(MPI_GROUP_NULL!=group1) MPI_Group_free(&group1);
if(MPI_GROUP_NULL!=group2) MPI_Group_free(&group2);
if(MPI_COMM_NULL!=comm1) MPI_Comm_free(&comm1);
if(MPI_COMM_NULL!=comm2) MPI_Comm_free(&comm2);
MPI_Finalize();
}
代码执行结果如下:

可以看到:
a. MIN归约操作针对的是{0,2,4}
b. MAX归约操作针对的是{1,3,5}
c. SUM归约操作针对的是{0,1,2,3,4,5}
d. SUM与MIN或MAX归约操作在时间上可能是重叠的,参与归约操作的进程也有重叠,但在结果上没有互相干扰。
(7)组间通信域。不同的通信域之间也可以通信,核心的操作是需要构造一个新的通信域类型——组间通信域。与一般的通信域不同,组间通信域包含两个进程组:本地进程组,远程进程组。通过组间通信域可以实现上述两个不同进程组内进程之间的通信。组间通信域的创建,需要在本地组和远程组中的相关进程中都调用创建语句,而且创建语句的参数中local_leader和remote_leader还是对称的。
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h> int main(int argc, char *argv[])
{
MPI_Comm myComm; // 标示本地子组的组内通信域
MPI_Comm myFirstComm; // 组间通信域
MPI_Comm mySecondComm; // 组间通信域
int color; // split用到的key
int rank; MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank); // 划分子通信域
// split是如何划分的 翻阅了英文的mpi tutorial教程
// 通过split函数中第三个参数来控制 当前进程在新的通信域中的新rank值大小
color = rank % ;
MPI_Comm_split(MPI_COMM_WORLD, color, rank, &myComm); // 建立组间通信域
// 需要确定的问题是:
// 1. A1和A2构造的是01之间的通信域 A1的local leader和remote leader与A2的local leader和remote leader是不是互相对应的
// 2. 同理 B1和B2构造的是12之间的组间通信域 local leader和remote leader是否也是互相对应的
// 这是可以保证的 通过MPI_Comm_split语句中的第三个参数来保证
if (==color) {
// 01之间的组间通信域
// 1. 本地组的leader是0
// 2. remote组的leader在MPI_COMM_WORLD中的rank是1
// 3. tag是1 (tag起到什么作用?)
// 4. 组间通信域存在myFirstComm中
MPI_Intercomm_create(myComm, , MPI_COMM_WORLD, , , &myFirstComm); // A1
}
else if (==color) {
// 01之间的组间通信域
// 1. 本地组的leader是0 (本地组leader0应该是MPI_COMM_WORLD中的1 这是如何保证的?)
// 2. 同理, MPI_COMM_WORLD中的0应该是color=0那个组中rank为0的进程 这是如何保证的?
MPI_Intercomm_create(myComm, , MPI_COMM_WORLD, , , &myFirstComm); // A2
// 12之间的组间通信域
MPI_Intercomm_create(myComm, , MPI_COMM_WORLD, , , &mySecondComm); // B1
}
else if (==color) {
// 21之间的组间通信域
MPI_Intercomm_create(myComm, , MPI_COMM_WORLD, , , &myFirstComm); // B2
} if (==color || ==color) {
MPI_Comm_free(&myFirstComm);
}
else if (==color) {
MPI_Comm_free(&myFirstComm);
MPI_Comm_free(&mySecondComm);
}
MPI_Finalize();
}
【MPI学习7】MPI并行程序设计模式:MPI的进程组和通信域的更多相关文章
- 【MPI学习5】MPI并行程序设计模式:组通信MPI程序设计
相关章节:第13章组通信MPI程序设计. MPI组通信与点到点通信的一个重要区别就是:组通信需要特定组内所有成员参与,而点对点通信只涉及到发送方和接收方. 由于需要组内所有成员参与,因此也是一种比较复 ...
- 【MPI学习6】MPI并行程序设计模式:具有不连续数据发送的MPI程序设计
基于都志辉老师<MPI并行程序设计模式>第14章内容. 前面接触到的MPI发送的数据类型都是连续型的数据.非连续类型的数据,MPI也可以发送,但是需要预先处理,大概有两类方法: (1)用户 ...
- Java进阶7 并发优化2 并行程序设计模式
Java进阶7 并发优化2 并行程序设计模式20131114 1.Master-worker模式 前面讲解了Future模式,并且使用了简单的FutureTask来实现并发中的Future模式.下面介 ...
- 【MPI学习2】MPI并行程序设计模式:对等模式 & 主从模式
这里的内容主要是都志辉老师<高性能计算之并行编程技术——MPI并行程序设计> 书上有一些代码是FORTAN的,我在学习的过程中,将其都转换成C的代码,便于统一记录. 这章内容分为两个部分: ...
- 【MPI学习4】MPI并行程序设计模式:非阻塞通信MPI程序设计
这一章讲了MPI非阻塞通信的原理和一些函数接口,最后再用非阻塞通信方式实现Jacobi迭代,记录学习中的一些知识. (1)阻塞通信与非阻塞通信 阻塞通信调用时,整个程序只能执行通信相关的内容,而无法执 ...
- 【MPI学习3】MPI并行程序设计模式:不同通信模式MPI并行程序的设计
学习了MPI四种通信模式 及其函数用法: (1)标准通信模式:MPI_SEND (2)缓存通信模式:MPI_BSEND (3)同步通信模式:MPI_SSEND (4)就绪通信模式:MPI_RSEND ...
- Java并行程序设计模式小结
这里总结几种常用的并行程序设计方法,其中部分文字源自<Java程序性能优化>一书中,还有部分文字属于个人总结,如有不对,请大家指出讨论. Future模式 一句话,将客户端请求的处理过程从 ...
- 并行程序设计模式--Master-Worker模式
简介 Master-Worker模式是常用的并行设计模式.它的核心思想是,系统有两个进程协议工作:Master进程和Worker进程.Master进程负责接收和分配任务,Worker进程负责处理子任务 ...
- 转 Master-Worker模式 并行程序设计模式--Master-Worker模式
简介 Master-Worker模式是常用的并行设计模式.它的核心思想是,系统有两个进程协议工作:Master进程和Worker进程.Master进程负责接收和分配任务,Worker进程负责处理子任务 ...
随机推荐
- 读书笔记——OpenGL超级宝典
对于某些函数的理解 glClear和glClearColor glClearColor指定glClear清除特定缓冲区时使用的值. glFlush 让所有已发送的命令尽快的由实际的绘制引擎执行. gl ...
- linux 删除已输入的命令行
ctrl + w —往前删除一个单词,光标放在最末尾ctrl + k —删除到末尾,光标放在最前面(可以使用ctrl+a) —————————————————————-华丽的分割线ctl + u 删除 ...
- HTML5与触摸界面
习惯了开发典型的面向电脑端浏览器的网站在开发手机端网站或者移动App的时候面对很多新的问题,这些新的问题,在我看来或多或少会给浏览者在使用网站或App的时候带来不好的用户体验,对于一个产品级应用,用户 ...
- 记一次linux服务器问题处理过程
本周二的时候,涛哥找我,说明了一件事,在安装ganglia的时候,发生的一个问题. 在一台suse 10 sp1的服务器上,安装ganglia的一个依赖包,libconfuse.rpm,安装完成之后, ...
- SQL-一道特殊的字符串分解题目
本题不是一道直接的字符串拆解, 应用场景如下,表中有一个字段,是表示事件受影响的国家集合,使用逗号进行分隔,不幸的是,居然发现有些国家本身就带有逗号,这样在规范化的时候,如何准确地找到这些国家呢? 以 ...
- 探索 OpenStack 之(15):oslo.messaging 和 Cinder 中 MessageQueue 消息的发送和接收
前言:上一篇文章 只是 RabbitMQ 的科普,本文将仔细分析 Cinder 中 RabbitMQ 的各组件的使用.消息的发送和接收等.由于各流程步骤很多,本文只会使用若干流程图来加以阐述,尽量做到 ...
- WEB安全--业务安全漏洞
0x00 索引说明 在OWASP的分享,关于业务安全的漏洞检测模型. 0x01 身份认证安全 1 暴力破解 在没有验证码限制或者一次验证码可以多次使用的地方,使用已知用户对密码进行暴力破解或者用一个通 ...
- 【Android UI设计与开发】5.底部菜单栏(二)使用Fragment实现底部菜单栏
既然 Fragment 取代了TabActivity,当然 TabActivity 的能实现的菜单栏,Fragment 当然也能实现.主要其实就是通过菜单栏的点击事件切换 Fragment 的显示和隐 ...
- leetcode-Maximum Subarray
https://leetcode.com/problems/maximum-subarray/ Find the contiguous subarray within an array (contai ...
- HDU 1828 / POJ 1177 Picture --线段树求矩形周长并
题意:给n个矩形,求矩形周长并 解法:跟求矩形面积并差不多,不过线段树节点记录的为: len: 此区间线段长度 cover: 此区间是否被整个覆盖 lmark,rmark: 此区间左右端点是否被覆盖 ...