基于都志辉老师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的进程组和通信域的更多相关文章

  1. 【MPI学习5】MPI并行程序设计模式:组通信MPI程序设计

    相关章节:第13章组通信MPI程序设计. MPI组通信与点到点通信的一个重要区别就是:组通信需要特定组内所有成员参与,而点对点通信只涉及到发送方和接收方. 由于需要组内所有成员参与,因此也是一种比较复 ...

  2. 【MPI学习6】MPI并行程序设计模式:具有不连续数据发送的MPI程序设计

    基于都志辉老师<MPI并行程序设计模式>第14章内容. 前面接触到的MPI发送的数据类型都是连续型的数据.非连续类型的数据,MPI也可以发送,但是需要预先处理,大概有两类方法: (1)用户 ...

  3. Java进阶7 并发优化2 并行程序设计模式

    Java进阶7 并发优化2 并行程序设计模式20131114 1.Master-worker模式 前面讲解了Future模式,并且使用了简单的FutureTask来实现并发中的Future模式.下面介 ...

  4. 【MPI学习2】MPI并行程序设计模式:对等模式 & 主从模式

    这里的内容主要是都志辉老师<高性能计算之并行编程技术——MPI并行程序设计> 书上有一些代码是FORTAN的,我在学习的过程中,将其都转换成C的代码,便于统一记录. 这章内容分为两个部分: ...

  5. 【MPI学习4】MPI并行程序设计模式:非阻塞通信MPI程序设计

    这一章讲了MPI非阻塞通信的原理和一些函数接口,最后再用非阻塞通信方式实现Jacobi迭代,记录学习中的一些知识. (1)阻塞通信与非阻塞通信 阻塞通信调用时,整个程序只能执行通信相关的内容,而无法执 ...

  6. 【MPI学习3】MPI并行程序设计模式:不同通信模式MPI并行程序的设计

    学习了MPI四种通信模式 及其函数用法: (1)标准通信模式:MPI_SEND (2)缓存通信模式:MPI_BSEND (3)同步通信模式:MPI_SSEND (4)就绪通信模式:MPI_RSEND ...

  7. Java并行程序设计模式小结

    这里总结几种常用的并行程序设计方法,其中部分文字源自<Java程序性能优化>一书中,还有部分文字属于个人总结,如有不对,请大家指出讨论. Future模式 一句话,将客户端请求的处理过程从 ...

  8. 并行程序设计模式--Master-Worker模式

    简介 Master-Worker模式是常用的并行设计模式.它的核心思想是,系统有两个进程协议工作:Master进程和Worker进程.Master进程负责接收和分配任务,Worker进程负责处理子任务 ...

  9. 转 Master-Worker模式 并行程序设计模式--Master-Worker模式

    简介 Master-Worker模式是常用的并行设计模式.它的核心思想是,系统有两个进程协议工作:Master进程和Worker进程.Master进程负责接收和分配任务,Worker进程负责处理子任务 ...

随机推荐

  1. MySQL数据库初识(二)

    8. 向数据表中插入数据记录(INSERT): 向数据表中插入数据记录有两种方法: 基本语法1:INSERT INTO 数据表 (字段名1,字段名2,字段名3……字段名n) VALUES (数据值1, ...

  2. 《SQL Server企业级平台管理实践》读书笔记——SQL Server数据库文件分配方式

    1.文件分配方式以及文件空间检查方法 最常用的检查数据文件和表大小的命令就是:sp_spaceused 此命令有三个缺陷:1.无法直观的看出每个数据文件和日志文件的使用情况.2.这个存储过程依赖SQL ...

  3. ArcGIS API for JavaScript Beta初步试探(一)

    这段时间一直在看https://developers.arcgis.com/javascript/beta/sample-code/index.html, 下面直接看图片: 叠加了二维arcgis s ...

  4. JQ插件

    什么是插件 插件(plugin)是JQuery的扩展(Extension),以JQuery的核心代码为基础,是一种遵循一定规范的应用程序接口编写出来的程序. 插件的引入 引入jquery.js文件 引 ...

  5. (一)openwrt源码目录概述

    前言 这段时间总是在和openwrt打交道,之前也零零散散地写过一点,还是希望能有点体系.还记得我刚看到源代码的时候,觉得无从下手.我想从Makefile的整个执行过程入手,搞清楚编译源代码的几个小时 ...

  6. Spring4定时器 cronTrigger和simpleTrigger实现方法

    spring4定时器 cronTrigger和simpleTrigger实现方法 Quartz 是个开源的作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制.Quartz 允许 ...

  7. Class to connect postgres with python in psycopg2

    For we need to connect the postgres db in project very frequently, so write the follows class: impor ...

  8. 【ASP.NET 进阶】根据IP地址返回对应位置信息

    其实就是使用了百度的IP库的功能接口,然后处理下就行了,效果图如下: 准备工作: 1.注册成为开度开发者,创建应用获得百度API调用的AK秘钥,百度开发中心地址:http://developer.ba ...

  9. DP+单调队列 codevs 1748 瑰丽华尔兹(还不是很懂具体的代码实现)

    codevs 1748 瑰丽华尔兹 2005年NOI全国竞赛  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 大师 Master 题解       题目描述 Descripti ...

  10. 最长回文子串Manacher算法模板

    Manacher算法能够在O(N)的时间复杂度内得到一个字符串以任意位置为中心的回文子串.其算法的基本原理就是利用已知回文串的左半部分来推导右半部分. 首先,在字符串s中,用rad[i]表示第i个字符 ...