文章目录
并行与分布式计算 第三章 进程级的并行:MPI编程
3.1 进程级并行的概念
3.1.1 多进程工作模式
主从模式
- 将一个待求解的任务分成一个主任务(主进程)和一些从任务(子进程)
- 主进程负责将任务分解、派发和收集各个子任务的求解结果并最后汇总得到问题的最终解。
- 各子进程接收主进程发来的消息;并行进行各自计算;然后向主进程发回各自的计算结果
单控制流多数据流模式
- 首先需要将数据预先分配给各个计算进程
- 然后各个计算进程并行地完成各自的计算任务,包括计算过程中各进程间的数据交换(施行通信同步)
- 最后才将各计算结果汇集起来。
进程间通信
进程间通信(IPC,Inter-Process Communication)让程序员能够协调不同的进程,使之能在一个操作系统里同时运行,并相互传递、交换信息。
3.1.2 消息传递模型
- 在消息传递模型中,并行进程通过相互传递消息来交换数据
- 管道、消息队列、套接字等IPC方式都属于消息传递
** SEND & RECEIVE**
- 发送/接收(send/receive)是一对最基本的消息传递原语
• Pipe 的 write/read 操作(利用管道实现父子进程间的通信)
• Message Queue 或 Socket 上的 send/receive 操作 - 我们能接触到的绝大多数消息传递方式,都可以抽象为send/receive 操作
通信机制:同步 & 异步
• 在消息传递中,同步和异步是发送方对通信的两种不同
处理方式
• 同步:消息发送方等待消息接收方完成接收并响应,然
后开始处理其他工作
• 异步:发送方在发送消息后不等待响应,直接开始处理
其他工作
MPI 与 OPENMP的对比
MPI程序的特点
- 用户必须通过显式地发送和接收消息来实现处理机间的数据交换
- 每个并行进程均有自己独立的地址空间。
- 并行计算粒度大,特别适合于大规模可扩展并行算法
3.2 OPENMPI
MPI函数 | 功能 |
---|---|
MPI_Init(&argc, &argv) | 通知MPI系统进行所有初始化设置。 |
MPI_Finalize() | 清理MPI环境。调用此函数后,不能再调用其他MPI函数。 |
MPI_Comm_rank(MPI_COMM_WORLD, &rank) | 获取当前进程号。 |
MPI_Comm_size(MPI_COMM_WORLD, &size) | 获取可用的进程数量。 |
3.2.1 MPI 通信函数 SEND & RECEIVE
一个消息好比一封信
• 消息的内容,即信的内容,在MPI中称为消息缓冲(Message Buffer), 消息缓冲由三元组<起始地址,数据个数,数据类型>标识
• 消息的接收发送者,即信的地址,在MPI中成为消息封装(Message Envelop),消息信封由三元组<源/目标进程,消息标签,通信域>标识MPI_Send (buf, count, datatype, dest, tag, comm)
为什么需要消息标签?
当发送者连续发送两个相同类型消息给同一个接收者,如果没有消息标签,接收者将无法区分这两个消息
数据类型
- MPI的特性之一是所有的通信函数都带一个数据类型参数,用于描述发送和接受数据的类型
- 你可以创建自己的数据类型
- 使用数据类型参数是为了在异构环境中,例如在具有不同字节存储顺序或者不同基本数据类型长度的异构计算及系统上,当数据类型被指定后,MPI能够在内部转换成相应的字节数,保证通信顺利进行。
COMMUNICATOR(通信器)
- 进程可以被划分成组,每个组用来处理某项特定任务
- 每条消息都应该在同样的上下文中发送和接收
- 这样的分组以及消息传递上下文,组合在一起被称为通信器 communicator
- MPI_COMM_WORLD 是默认的通信器,如果没有分组的需求,直接使用这个通信器就可以
MPI_STATUS
接收方在调用MPI_Recv时,会提供一个 MPI_Status结构体作为参数,该结构体包含了 一些关于消息的信息:
• 发送端rank,在MPI_SOURCE字段中 (stat.MPI_SOURCE)
• 消息标签,在MPI_TAG中(stat.MPI_TAG)
• 消息长度,通过 MPI_Get_count(MPI_Statusstatus, MPI_Datatype datatype, int count) 函数读出
3.2.2点到点通信示意图
阻塞通信(阻塞发送)
阻塞发送意味着,从函数参数列表中指定位置复制数据之前,发送函数不会返回,因此可以在发送函数调用后更改数据而不会影响原始消息。
MPI的四种点对点通信模式
通信模式(Communication Mode)指的是缓冲管理,以及发送方和接收方之间的同步方式。
同步通信
• 只有相应的接收过程已经启动,发送过程才正确返回。
• 因此,同步发送返回后,表示发送缓冲区中的数据已经全 部被系统缓冲区缓存,并且已经开始发送。
• 当同步发送返回后,发送缓冲区可以被释放或者重新使用
缓冲通信
缓冲通信模式的发送不管接收操作是否已经启动都可以执 行,但是需要用户程序事先申请一块足够大的缓冲区,通 过MPI_Buffer_attch实现,通过MPI_Buffer_detach来回收申 请的缓冲区。
标准通信
就绪通信
• 发送操作只有在接收进程相应的接收操作已经开始才进行发送。
• 当发送操作启动而相应的接收还没有启动,发送操作将出错。
• 就绪通信模式的特殊之处就是接收操作必须先于发送操作启动。
阻塞通信返回的条件:
• 通信操作已经完成,也就是消息已经发送或接收;
• 调用的缓冲区可用。若是发送操作,则该缓冲区可以被其它的操作更新;若是接收操作,该缓冲区的数据已经完整,可以被正确引用。
非阻塞通信
非阻塞的通信函数是立即返回的,在这种异步的情况下我们并不知道发送/接收是否成功,因此需要一个Request对象作为Handler(句柄)来检查数据发送状态,MPI还提供了对非阻塞通信完成的检测,主要的有两种:MPI_Wait函数和MPI_Test函数。
3.2.3 N V N (集群通信)
群集通信(Collective Communications)是一个进程组中的所有进 程都参加的全局通信操作。两种分类方式:功能分类,方向分类
功能分类
• 通信功能:主要完成组内数据的传输
• 聚集功能:在通信的基础上对给定的数据完成一定的操作
• 同步功能:实现组内所有进程在执行进度上取得一致
方向分类
• 一对多通信:一个进程向其它所有的进程发送消息,这个负责发送消息的进程叫做
Root进程。
• 多对一通信:一个进程负责从其它所有的进程接收消息,这个接收的进程也叫做
Root进程。
• 多对多通信:每一个进程都向其它所有的进程发送或者接收消息。
集合通信同步
集合通信在进程间引入了同步点(Barrier路障)的概念。这意味着所有的进程在执行代码的时候必须首先都到达一个同步点才能继续执行后面的代码
如果你需要对程序显式地进行同步,也可以使用屏障指令:MPI_Barrier(MPI_Comm communicator)
广播 MPI_Bcast
广播用来从根节点将数据传给communicator中的所有进程
分发 MPI_Scatter
分发是从根节点将一组数据中的每一部分分别发送给communicator中的每个进程,每个进程收到的数据可以不同
收集 MPI_Gather
全局收集VS 全局交换
规约 REDUCE
规约是函数式编程中的概念,它接受一组数据,并输出更小的一组数字,如 sum([1,2,3,4])=10,MPI提供函数来在各个进程之间进行规约操作
MPI规约操作 | 功能 |
---|---|
MPI_MAX | 返回最大元素 |
MPI_MIN | 返回最小元素 |
MPI_SUM | 对元素求和 |
MPI_PROD | 将所有元素相乘 |
MPI_LAND | 对元素执行逻辑与运算 |
MPI_LOR | 对元素执行逻辑或运算 |
MPI_BAND | 对元素的各个位按位与执行 |
MPI_BOR | 对元素的位执行按位或运算 |
MPI_MAXLOC | 返回最大值和所在的进程的秩 |
MPI_MINLOC | 返回最小值和所在的进程的秩 |
3.2.4 单边通信
• 单边通信又称作远端内存访问(Remote Memory Access,RMA)
• 无论点到点通信或集合通信,都需要发送方和接收方配合,是基于同步的消息传递方式
• 单边通信将数据传递和同步两个操作解耦,每个进程将一部分内存暴露给其他进程,其他进程可以任意访问该内存区域,在不需同步的情况下传递数据
• 使用单边通信时,要先创建窗口(MPI_Win),然后在窗口上进行单边通信操作
创建和销毁窗口
单边通信操作 PUT
单边通信操作 get
单边通信操作 原子加法