基于MPI的并行程序设计.doc
- 文档编号:143202
- 上传时间:2022-10-04
- 格式:DOC
- 页数:10
- 大小:46.50KB
基于MPI的并行程序设计.doc
《基于MPI的并行程序设计.doc》由会员分享,可在线阅读,更多相关《基于MPI的并行程序设计.doc(10页珍藏版)》请在冰豆网上搜索。
基于MPI的并行程序设计
1、消息传递并行程序的基本原理
1.1消息传递的基本概念
MP(messagepassing)消息传递模型:
采用消息传递模型的程序由一组进程构成,每个进程只能访问本地的(自己)的存储器空间,在不同进程之间的通信通过发送和接收消息来完成。
根据这个定义,在消息传递模型下,不同进程之间的数据传输由发送进程和接收进程共同完成。
由于支持消息通信对系统的硬件和软件的要求都不高,因此消息传递模型在并行程序设计中被广泛采用。
最简单的可以采用消息传递方式编程的并行计算机系统包括多个处理器,每个处理器有自己的存储器,他们用某种形式的互联网络连接在一起。
因此,消息传递模型不仅可以用来编写分布内存并行计算机系统的程序,也可以用来编写集群系统上的程序。
而在共享存储器系统中,消息传递可以用共享存储器来代替互连网络,因此,消息传递模型具有可以适应多种体系结构的要求。
从软件的角度来说,采用消息传递的系统通常以消息传递库的形式出现,库中包含了发送了接收消息所需要的函数。
这使得可以以现有的串行程序语言为基础来开发消息传递的程序。
一个消息传递的库从严格意义上来说,只需要提供两个函数:
一个用来发送消息,一个用来接收消息,但事实上,绝大多数最近出现的消息传递库比如CMMD,NX,MPL和MPI都提供了额外的函数调用来进行复杂的通信操作,比如在一组处理器中进行集合通信的操作。
2、点到点通信
主要的点到点通信操作是SEND和RECEIVE。
SEND把一条消息从一个处理器发送到另外一个,而RECEIVE则读取来自其他处理器的消息。
在最简单的情况下,对SEND和RECEIVE的调用不会立即返回,除非实际的操作已经完成(消息发送完毕或者消息接收完毕)。
这种形式的操作被称为阻塞SEND和RECEIVE。
一个阻塞的SEND只有在对应的RECEIVE操作已经被调用(不一定结束)并且消息已经被发送的情况下才会顺利返回。
同样的,一个阻塞RECEIVE只有在对应的SEND操作已经调用并且消息已经成功地接收的情况下才会顺利返回(这里暂时不讨论发生异常比如调用出错的情况)。
对阻塞操作来说,每次处理器进行SEND和RECEIVE调用时它需要等待的时间不仅包括传输数据所需的时间,还包括对应的处理器对匹配的操作进行调用的时间。
因此在消息传递过程中,除非SEND和RECEIVE操作同时调用,总有一些处理器处在等待状态,这增加了程序执行的额外开销。
SEND和RECEIVE操作通常有另外一种形式,称为非阻塞式通信。
一个非阻塞SEND和RECEIVE操作并不等待实际的消息传送完全结束(只要底层系统保证会完成剩下的工作就行),它们就开始执行下面的操作(当然这些操作不能和SEND/RECEIVE的结果有依赖关系)。
在适当的时候,处理器可以检查刚才的非阻塞SEND/RECEIVE调用是否完成了,以决定下一步的操作。
除了点对点通信,还有集合通信。
3、MPI程序设计基础
3.1MPI简介
MPI(MessagePassingInterface)是一种基于消息传递的并行程序设计标准,它明确定义了一整套用户接口,而对于具体实现,除了给出了建议以外,并没有太多的限制。
由于它在标准化方面所进行的努力,它已经成为了消息传递并行程序程序设计的代表和事实上的标准。
在MPI标准的制定过程中,制定者希望MPI能够达到下面的三个目标:
较高的通信性能
较好的程序可移植性
可以满足消息传递程序设计的各种要求
由于MPI是一个库而不是一种程序语言,因此对MPI的使用必须和特定的程序语言结合起来进行。
通常情况下,对一个MPI的实现,对FORTRAN和C语言的支持是基本的要求。
3.2MPI的实现
在实际的系统中,MPI以程序库的形式出现,通过库函数接口给用户提供MPI规范定义的功能。
这样的库被称为MPI实现。
SUN公司提供的SUNClusterTools即是一个MPI的实现
一个简单的C语言版MPI程序
//simple.c
#include“mpi.h”
#inlucde
#include
intmain(intargc,char**argv)
{
intmyid,numprocs;
intnamelen;
charprocessor_name[MPI_MAX_PROCESSOR_NAME];
//MPIInitializationphase
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
MPI_Get_processor_name(processor_name,&namelen);
//Theworkingphase
Printf(“ThisisProcess%dof%don%s\n”,myid,numprocs,processor_name);
//MPIFinalizationphase
MPI_Finalize;
}
用mpicc命令将这个程序编译:
mpicc–osimplesimple.c
然后用mpirun来运行这个程序(假定已经设置好了配置文件,关于MPI环境的配置可以参考第三章SunClustertools的安装配置)。
mpirun–np4simple
为这个程序指定四个工作进程,如果这个程序在一个集群系统的某台计算机cluster1上运行,它的输出结果(可能)如下:
ThisisProcess0of4oncluster1
ThisisProcess2of4oncluster1
ThisisProcess1of4oncluster1
ThisisProcess3of4oncluster1
如果这个程序在一个集群系统的四台不同计算机cluster1-cluster4上运行,它的输出结果(可能)如下:
ThisisProcess0of4oncluster1
ThisisProcess2of4oncluster3
ThisisProcess1of4oncluster2
ThisisProcess3of4oncluster4
从上边的例子可以看出,编写一个MPI程序,在配置好MPI的环境之后,有以下特点:
1)包含MPI的头文件声明,如例子中的#include"mpi.h"
2)MPI相关变量的声明,如例子中的intmyid,numprocs;等,声明了程序的id和总的进程数
3)MPI初始化过程,MPI函数调用,获得程序必须的系统信息,如例子中的
MPI_Init(&argc,&argv);
3)通过MPI的通信,包含在程序体中,如例子中的MPI_Comm_rank(MPI_COMM_WORLD,&myid);是用来得到当前进程号的通信接口,MPI的主要功能即提供进程间通信的接口。
5)MPI结束过程,释放系统资源。
如例子中的MPI_Finalize;
MPI程序的一些惯例
MPI命名规范
所有MPI的名字都有前缀“MPI_”,不管是常量、变量还是函数调用的名字都是这样。
而在用户程序中自己定义的常量、变量、过程和函数调用不要以“MPI_”开头,以免造成错误。
FORTRAN形式的MPI调用,一般全为大写(虽然FORTRAN语法不区分大小写),而C形式的MPI调用,则为MPI_Xxxx_xxx的形式(如上边的MPI_Comm_rank())。
MPI返回值
所有MPI的FORTRAN子程序在最后的参数中都有一个返回代码,对于成功的函数调用,返回代码包含的值为MPI_SUCCESS,对于失败的函数调用,其错误代码依赖于具体的MPI实现。
一些MPI操作是函数,没有这个参数,对MPI的C语言绑定,这个返回代码由函数的返回值直接给出,而不再作为参数。
3.3MPI调用接口
在MPI-1中,共有128个调用借口,而在MPI-2中有287个,SUNClusterTools是MPI-2标准的一个实现。
MPI的基本功能以MPI初始化,MPI结束,得到当前进程号,得到通信域中包含的进程数,发送消息,消息接收六个接口最为常用,下边分别以C语言的实现做基本的介绍。
MPI的参数有三种,分别是IN,OUT和INOUT。
它们表达的含义分别是:
IN(输入):
调用部分传递给MPI的参数,MPI除了使用该参数外在系统内部不会对该参数进行任何修改;
OUT(输出):
MPI使用这个参数来给调用者返回结果,系统内部不会使用调用者设定的初值。
INOUT(输入输出):
该参数首先被调用者用作IN参数,然后被MPI用作输出参数。
MPI初始化
intMPI_Init(int*argc,char**argv)
MPI_Init()为MPI程序的第一个调用,它完成MPI程序的初始化工作。
在调用其他MPI函数之前,所有的MPI程序都需要调用这个函数。
MPI结束
intMPI_Finalize(void)
MPI_Finalize()是MPI程序的最后一个调用,它结束MPI程序的运行,应该是MPI程序最后一条可执行语句,否则程序的运行结构可能会出现无法预料的结果。
得到当前进程号
intMPI_Comm_rank(MPI_Commcomm,int*rank)
其中comm为通信域描述符,rank返回调用进程在这个通信域中的进程号。
对MPI的C语言绑定来说,进程号从0开始。
同一MPI程序中的所有进程被系统赋予不同的进程号,这个进程号使得进程可以进行自我定位,将自己和其他的进程区别开,从而同一程序中的各进程可以相互协作共同完成计算任务。
在SPMD中,它通常和MPI_Comm_size()调用结合起来来确定每个工作进程的任务分配。
得到通信域中包含的进程数
intMPI_Comm_size(MPI_Commcomm,int*size)
其中comm为通信域描述符,size返回调用进程在这个通信域中的工作进程数。
发送消息
intMPI_Send(void*buf,intcount,MPI_Datatypedatatype,intdest,inttag,MPI_Commcomm)
这是MPI的基本发送函数。
MPI_SEND函数将发送缓冲区buf中的count个datatype数据类型的数据发送到目的进程dest(目的进程在通信域comm中的进程号),tag为消息标签,通过使用它,可以把本次发送的消息与这两个进程间其他的消息区分开。
MPI_SEND操作中指定的发送缓冲区buf是一个count个类型为datatype的数据组成的连续的数据块,buf是这个数据块的首地址。
需要注意的是count不是字节数。
其中的data_type数据类型可以是MPI的预定义类型,也可以是用户在MPI预定义类型基础上构造出来的自定义类型。
消息接收
intMPI_Recv(void*buf,intcount,MPI_Datatypedatatype,intsource,inttag,MPI_Commcomm,MPI_Status*status)
这是MPI的基本接收函数。
MPI_RECV从指定的通信域comm中进程号为source的进程接收count个数据类型为datatype的数据,接收的数据被存放在接收缓冲区buf中,所接收的消息的消息标志必须为tag。
status用来向调用者返回本次接收操作的状态。
需要注意的是,调用者在调
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 MPI 并行 程序设计