并行计算:MPI总结

一、MPI简介

1.什么是MPI

Massage Passing Interface:是消息传递函数库的标准规范,由MPI论坛开发。

  • 一种新的库描述,不是一种语言。共有上百个函数调用接口,提供与C和Fortran语言的绑定
  • MPI是一种标准或规范的代表,而不是特指某一个对它的具体实现
  • MPI是一种消息传递编程模型,并成为这种编程模型的代表和事实上的标准

2.MPI的特点

MPI有以下的特点:

  • 消息传递式并行程序设计
    指用户必须通过显式地发送和接收消息来实现处理机间的数据交换。
    在这种并行编程中,每个并行进程均有自己独立的地址空间,相互之间访问不能直接进行,必须通过显式的消息传递来实现。
    这种编程方式是大规模并行处理机(MPP)和机群(Cluster)采用的主要编程方式。

  • 并行计算粒度大,特别适合于大规模可扩展并行算法
    用户决定问题分解策略、进程间的数据交换策略,在挖掘潜在并行性方面更主动,并行计算粒度大,特别适合于大规模可扩展并行算法

  • 消息传递是当前并行计算领域的一个非常重要的并行程序设计方式

二、MPI的基本函数

MPI调用借口的总数虽然庞大,但根据实际编写MPI的经验,常用的MPI函数是以下6个:

  • MPI_Init(…);
  • MPI_Comm_size(…);
  • MPI_Comm_rank(…);
  • MPI_Send(…);
  • MPI_Recv(…);
  • MPI_Finalize();

三、MPI的通信机制

MPI是一种基于消息传递的编程模型,不同进程间通过消息交换数据。

1.MPI点对点通信类型

所谓点对点的通信就是一个进程跟另一个进程的通信,而下面的聚合通信就是一个进程和多个进程的通信。

MPI消息传递过程

在这里插入图片描述
(1)标准模式
在这里插入图片描述
非缓冲
该模式下MPI有可能先缓冲该消息,也可能直接发送,可理解为直接送信或通过邮局送信。是最常用的发送方式。

由MPI决定是否缓冲消息

  • 没有足够的系统缓冲区时或出于性能的考虑,MPI可能进行直接拷贝:仅当相应的接收完成后,发送语句才能返回。

    这里的系统缓冲区是指由MPI系统管理的缓冲区。而非进程管理的缓冲区。
    MPI环境定义有三种缓冲区:应用缓冲区、系统缓冲区、用户向系统注册的通信用缓冲区

  • MPI缓冲消息:发送语句在相应的接收语句完成前返回。

这时后发送的结束或称发送的完成== 消息已从发送方发出,而不是滞留在发送方的系统缓冲区中。

该模式发送操作的成功与否依赖于接收操作,我们称之为非本地的,即发送操作的成功与否跟本地没关系。

(2)缓冲模式
在这里插入图片描述
可理解为通过邮局送信(应用缓冲区)。注意这里是应用缓冲区,和系统缓冲区不同。需要用户程序事先申请一块足够大的缓冲区,用户定义的缓冲区只能用于缓存模式,一个进程一次只能绑定一块用户缓冲区,通过MPI_Buffer_attch实现

发送是本地的: 完成不依赖于与其匹配的接收操作。发送的结束仅表明消息进入用户指定的缓冲区中。

通过MPI_Buffer_detach来回收申请的缓冲区,阻塞模式下该操作直到缓存区的数据传输完才返回。

缓冲模式在相匹配的接收未开始的情况下,总是将送出的消息放在缓冲区内,这样发送者可以很快地继续计算,然后由系统处理放在缓冲区中的消息。

占用额外内存,一次内存拷贝。

其函数调用形式为:MPI_BSEND(…)。B代表缓冲.

(3)同步模式

在这里插入图片描述
可理解为握手后才送出名片

本质特征:收方接收该消息的缓冲区已准备好,不需要附加的系统缓冲区

任意发出:发送请求可以不依赖于收方的匹配的接收请求而任意发出

成功结束:仅当收方已发出接收该消息的请求后才成功返回,否则将阻塞。

非本地的

可用于实现进程同步

其函数调用形式为:MPI_SSEND(…)。S代表同步

(4)就绪模式

在这里插入图片描述
可理解为有客户请求,才提供服务。

发送请求仅当有匹配的接收后才能发出,否则出错。在就绪模式下,系统默认与其相匹配的接收已经调用。接收必须先于发送。

它依赖于接收方的匹配的接收请求,不可以任意发出。

其函数调用形式为:MPI_RSEND(…)。R代表就绪 。

正常情况下可用标准模式替换,除可能影响性能外,不影响结果。

(5)点对点通信的阻塞性分析

上面的四种方式都有阻塞通信和非阻塞通信的两种版本

  • 阻塞通信
    就是按照上面的流程进程自己要等待指定的操作实际完成,或者所涉及的数据被MPI系统安全备份后,函数才返回后才能进行下一步的操作。
  • 非阻塞通信
    在这里插入图片描述
    通信函数总是立即返回,实际操作由MPI后台进行,需要调用其它函数来查询通信是否完成,通信与计算可重叠。

因为阻塞通信时保证了数据的安全性,所以通信还是返回后,其他的函数或者语句能够对这些数据资源直接访问。

但是非阻塞通信函数立即返回,不能保证数据已经被传送出去或者被备份或者已经读入使用,所以即使你没有阻塞,后面的语句可以继续执行,如果你要操纵上面所说的数据,将会导致发送或接收产生错误。所以对于非阻塞操作,要先调用等待MPI_Wait()或测试MPI_Test()函数来结束或判断该请求,然后再向缓冲区中写入新内容或读取新内容。

所以非阻塞性的通信函数一般时用到后面的语句跟本函数数据无冲突的场景,可以提高效率。

如何使用两种版本?

发送语句的前缀由MPI_改为MPI_I, I指的是immediate,即可改为非阻塞,否则是阻塞。示例如下:

标准模式:MPI_Send(…)->MPI_Isend(…)

Buffer模式:MPI_Bsend(…)->MPI_Ibsend(…)

(6) 通信函数的返回和通信函数的完成、和通信的完成

通信的完成=发送函数的完成+接收函数的完成

在阻塞状态下通信函数的返回是在通信即将完成或者完成之后(根据不同的模式有不同设置,如缓冲模式发送函数的返回是在缓冲区的数据传输完之后返回)。在非阻塞状态下,通信函数立即返回。

下面讲讲通信函数的完成:

  • 发送的完成: 代表发送缓冲区中的数据已送出,发送缓冲区可以重用。它并不代表数据已被接收方接收。数据有可能被缓冲;
    这里有一个特例,就是同步模式,它的发送完成==接收方已初始化接收,数据将被接收方接收。

  • 接收的完成:代表数据已经写入接收缓冲区。接收者可访问接收缓冲区,status对象已被释放。它并不代表相应的发送操作已结束(即操作函数可返回)。

通信函数的返回和通信函数完成是不一样的。

通过MPI_Wait()和MPI_Test()来判断通信是否已经完成;

(7) 非阻塞发送和接收

int MPI_Isend(void* buf, int count, MPI_Datatype datatype, int dest, int tag, 
								MPI_Comm comm, MPI_Request *request)
								
	IN buf 发送缓冲区的起始地址
	IN count 发送缓冲区的大小(发送元素个数)
	IN datatype 发送缓冲区数据的数据类型
	IN dest 目的进程的rank值
	IN tag 消息标签
	IN comm 通信空间/通信域
	OUT request  非阻塞通信完成对象(句柄)
	MPI_Ibsend/MPI_Issend/MPI_Irsend:非阻塞缓冲模式/非阻塞同步模式/非阻塞就绪模式
int MPI_Irecv(void* buf, int count, MPI_Datatype datatype, int source, int tag,
				MPI_Comm comm, MPI_Request* request)

(8)消息探测

MPI_Probe()和MPI_Iprobe()函数探测接收消息的内容。用户根据探测到的消息内容决定如何接收这些消息,如根据消息大小分配缓冲区等。前者为阻塞方式,即只有探测到匹配的消息才返回;后者为非阻塞,即无论探测到与否均立即返回.

int MPI_Probe(int source, int tag, MPI_Comm comm, MPI_Status* status)
int MPI_Iprobe(int source, int tag, MPI_Comm comm, int*flag, MPI_Status* status)
IN source 数据源的rank,可以是MPI_ANY_SOURCE
IN tag      数据标签,可以是MPI_ANY_TAG
IN comm  通信空间/通信域
OUT flag   布尔值,表示探测到与否(只用于非阻塞方式)
OUT status status对象,包含探测到消息的内容

(8)通信检查

int MPI_Wait(MPI_Request* request, MPI_Status * status) 
通信检测函数:必须等待指定的通信请求完成后才能返回,成功返回时,
status 中包含关于所完成的通信的消息,相应的通信请求被释放,即request 被置成MPI_REQUEST_NULL
int MPI_Test(MPI_Request *request,int *flag, MPI_Status *status
通信检测函数:不论通信是否完成都立刻返回,flag为1表示通信完成

其他通信检测函数

int MPI_Waitany(int count,MPI_Request *array_of_requests,int *index, MPI_Status *status)
int MPI_Waitall(int count,MPI_Request *array_of_requests,MPI_Status *array_of_statuses)
int MPI_Waitsome(int incount,MPI_Request *array_of_requests,int *outcount,
				 int *array_of_indices,MPI_Status *array_of_statuses)
int MPI_Testany(int count,MPI_Request *array_of_requests,int *index, int *flag,MPI_Status *status)
int MPI_Testall(int count,MPI_Request *array_of_requests,int *flag,MPI_Status *array_of_statuses)
int MPI_Testsome(int incount,MPI_Request *array_of_requests,int *outcount,
				int *array_of_indices,MPI_Status *array_of_statuses)

(9)请求释放和请求撤销

  • MPI_Request_free(MPI_Request request)

    释放指定的通信请求(及所占用的内存资源)

    若该通信请求相关联的通信操作尚未完成,则等待通信的完成,因此通信请求的释放并不影响该通信的完成

    该函数成功返回后request 被置为MPI_REQUEST_NULL

    一旦执行了释放操作,该通信请求就无法再通过其它任何的调用访问

  • MPI_Cancel(MPI_Request request)
    非阻塞型,用于取消一个尚未完成的通信请求
    在MPI系统中设置一个取消该通信请求的标志后立即返回,具体的取消操作由MPI系统在后台完成。
    MPI_CANCEL允许取消已调用的通信请求,但并不意味着相应的通信一定会被取消:若相应的通信请求已经开始,则它会正常完成,不受取消操作的影响;若相应的通信请求还没开始,则可以释放通信占用的资源。
    调用MPI_CANCEL 后,仍需用MPI_WAIT,MPI_TEST或MPI_REQUEST_FREE 来释放该通信请求。

  • MPI_Test_cancelled(MPI_Status status,int *flag)
    检测通信请求是否被取消

(9)MPI点对点通信的安全性

  • 进程死锁

在这里插入图片描述

  • 不安全的通信

在这里插入图片描述在这里插入图片描述

这里之所以会不安全,是因为两个进程都需要buffer。但仅仅只有两个进程时,程序不会发生问题,因为系统缓冲区够用,但是当有100000个进程的时候就会出现死锁。比如现在A,B是刚刚进入的线程,前面的进程使得系统缓冲区已经满了,A,B都被阻塞,因此C、D也会被阻塞,这两个程序就会陷入死锁。

  • 安全的通信
    在这里插入图片描述

2.MPI聚合通信

上面是点对点通信,聚合通信就是包括了一对多,多对一和多对多的通信方式。
在这里插入图片描述
(1) MPI_Bcast
函数原型
int MPI_Bcast (
 void buffer, /* 发送/接收buf/
 int count, /*元素个数*/
 MPI_Datatype datatype,
 int root, /*指定根进程*/
 MPI_Comm comm)
根进程既是发送缓冲区也是接收缓冲区
原理图
示例:

int p, myrank; 
float buf;
MPI_Comm comm;
MPI_Init(&argc, &argv);
/*得进程编号*/
MPI_Comm_rank(comm, &my_rank);
/* 得进程总数 */
MPI_Comm_size(comm, &p);
if(myrank==0)
	   buf = 1.0;
MPI_Bcast(&buf,1,MPI_FLOAT,0, comm);

(2) MPI_Gather

Root进程从n个进程的每一个接收各个进程(包括它自已)的消息. 这n个消息的连接按序号rank进行, 存放在Root进程的接收缓冲中.

int MPI_Gather ( 
   	 void *sendbuf,
   	 int sendcnt,
   	 MPI_Datatype sendtype, 
   	 void *recvbuf, 
   	 int recvcount,
   	 MPI_Datatype recvtype, 
   	 int root, 
   	 MPI_Comm comm )

在这里插入图片描述

int p, myrank; 
float data[10];/*分布变量*/
float* buf;
MPI_Comm comm;
MPI_Init(&argc, &argv);
/*得进程编号*/
MPI_Comm_rank(comm,&my_rank);
/* 得进程总数 */
MPI_Comm_size(comm, &p);
if(myrank==0)
	buf=(float*)malloc(p*10*sizeof(float);/*开辟接收缓冲区*/

MPI_Gather(data,10,MPI_FLOAT,
	buf,10,MPI_FlOAT,0,comm);

想要了解更多函数的用法,可以到官方文档查看。
同时如果想要练习这些函数的用法,可以到超算习堂进行练习。

  • 63
    点赞
  • 389
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MPI(Message Passing Interface)是一种用于并行计算的标准编程模型,可以在多个处理器之间进行通信和协作。MPI并行计算pdf是指使用MPI编写的并行程序,用于对pdf文件中的数据进行并行处理和计算MPI并行计算pdf的基本步骤如下: 1. 并行化:将pdf文件分割成多个部分,每个部分分配给不同的处理器进行处理。这可以通过将pdf文件划分成多个子文件或者划分成多个页面来实现。 2. 数据分发:将划分好的pdf文件分发到不同的处理器上。每个处理器负责处理自己分配到的部分。 3. 并行计算:每个处理器独立地对其分配到的pdf部分进行计算。这可以包括对pdf文件进行解析、提取关键信息、进行数值计算等操作。 4. 数据合并:每个处理器完成计算后,将计算结果合并到一个主处理器上。合并的方式可以是将每个处理器的计算结果发送给主处理器,或者通过共享内存等方式进行合并。 5. 结果输出:将合并后的计算结果输出到一个文件或者打印出来,供后续分析和使用。 MPI并行计算pdf的优势在于能够充分利用多个处理器的计算能力,加快计算速度。同时,MPI还提供了通信和同步机制,保证并行计算的正确性和一致性。 然而,MPI并行计算pdf也存在一些挑战。首先,需要对pdf文件进行合理的划分,以便能够有效地利用不同处理器的计算资源。其次,需要进行复杂的通信和同步操作,以保证多个处理器之间的数据一致性和正确性。此外,还需要解决处理器之间的负载均衡问题,避免某些处理器过载而导致整体计算速度下降。 综上所述,MPI并行计算pdf是一种高效的并行计算方法,可以提高pdf数据处理的效率和速度。但是需要合理划分数据、解决通信同步问题和处理负载均衡等挑战。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值