2020/2/61MPI并行程序设计MPI是目前最重要的并行编程工具,它具有移植性好、功能强大、效率高等多种优点,而且有多种不同免费、高效、实用的实现版本,几乎所有的并行计算机厂商都提供对它的支持,这是其他的并行编程环境所无法比拟的。2020/2/62什么是MPI?MPI(MessagePassingInterface)MPI是一个库,而不是一门语言;MPI是一种标准或规范的代表,而不特指某一个对它的具体实现;MPI是一种消息传递编程模型,并成为这种编程模型的代表和事实上的标准;2020/2/63消息传递模型假设底层的消息传递模型是一组处理器,每一个处理器有自己的本地内存,并且通过互连网络实现与其他处理器的消息传递处理器内存处理器内存处理器内存处理器内存处理器内存处理器内存处理器内存互连网络处理器内存2020/2/64MPI并行程序设计MPI历史机房集群环境六个接口构成的MPI子集MPI并行程序的两种基本模式MPI并行程序的通信模式2020/2/65MPI的历史MPI初稿:美国并行计算中心工作会议(92年4月)MPI-1公布:第一届MPI大会(93年2月)MPI标准正式发布:1994年5月MPI-1.1发布:1995年6月MPI-2发布:(以前的版本统称MPI-1)1997年7月2020/2/66MPI的实现MPICH:最重要的MPI实现与MPI-1规范同步发展的版本支持部分MPI-2的特征(如动态生成进程等)LAM(LocalAreaMulticomputer)OhioStateUniversity开发它主要用于异构的计算机网络计算系统2020/2/67下载地址MPICH2(最新版本1.0.3)LAM-MPI(最新版本7.1.2)机房环境软件部分操作系统:WindowsServer2003MPI实现:MPICH-1.2.5硬件部分集群系统有4个刀片(每片主要参数):2CPU(Xeon3.2GHZ),2GBRAM,2(4)个千兆网卡,2个SCSI硬盘2020/2/69机房集群环境一个主节点(一个刀片)启用双网卡,设置内/外网IP地址,用于用户登陆、提交调试程序、管理员管理集群等。主节点开启SSH、Ftp等服务。三个从节点用于从主节点接受计算任务并执行计算(返回结果)。从节点开启SSH服务。节点之间的通信通过SSH协议来实现2020/2/610六个接口构成的MPI子集在MPI-1中,共有128个调用接口,在MPI-2中有287个,应该说MPI是比较庞大的。但是从理论上说,MPI所有的通信功能可以用它的6个基本的调用来实现,掌握了这6个调用,就可以实现所有的消息传递并行程序的功能。所有的MPI标识符,都以MPI前缀开头,后面紧跟一个大写字母和一系列小写字母以及下划线。MPI调用的参数说明IN:调用部分传递给MPI的参数,MPI除了使用该参数外不允许对这一参数做任何修改OUT:MPI返回给调用部分的结果参数,该参数的初始值对MPI没有任何意义INOUT:调用部分首先将该参数传递给MPI,MPI对这一参数引用、修改后,将结果返回给外部调用,该参数的初始值和返回结果都有意义2020/2/6111、MPI初始化:MPI_Init函数用法:MPI_Init(&argc,&argv)每一个MPI进程调用的第一个MPI函数都是MPI_Init。该函数指示系统完成所有的初始化工作,以备对后续MPI库的调用进行处理。2、MPI结束:MPI_Finalize函数用法:MPI_Finalize()在一个进程执行完其全部MPI库函数调用后,将调用函数MPI_Finalize,从而让系统释放分配给MPI的资源。它是MPI程序的最后一条可执行语句,否则程序的运行结果是不可预知的。2020/2/6123、确定进程的标识符用法:MPI_Comm_rank(MPI_COMM_WORLD,&id)当MPI初始化后,每一个活动进程变成了一个叫做MPI_COMM_WORLD的通信域中的成员。通信域是一个不透明的对象,提供了在进程之间传递消息的环境。在一个通信域内的进程是有序的。在一个有p个进程的通信域中,每一个进程有一个唯一的序号(ID号),取值为0~p-1。进程可以通过调用函数MPI_Comm_rank来确定它在通信域中的序号。4、确定进程数量用法:MPI_Comm_size(MPI_COMM_WORLD,&p)进程通过调用函数MPI_Comm_size来确定一个通信域中的进程总数。2020/2/6135、消息发送函数MPI_SEND(buf,count,datatype,dest,tag,comm)参数说明:INbuf:发送缓冲区的起始地址INcount:将要发送的数据的个数INdatatype:发送数据的数据类型INdest:目的进程标识号INtag:消息标志INcomm:通信域MPI_SEND将发送缓冲区中的count个datatype数据类型的数据发送到目的进程,目的进程在通信域中的标识号是dest,本次发送的消息标志是tag,使用这一标志,就可以把本次发送的消息和本进程向同一目的进程发送的其他消息区别开。2020/2/6146、消息接收函数MPI_RECV(buf,count,datatype,source,tag,comm,status)参数说明:OUTbuf:发送缓冲区的起始地址INcount:将发送的数据的个数INdatatype:发送数据的数据类型INdest:目的进程标识号INtag:消息标志INcomm:通信域OUTstatus:返回类型(是由三个域组成的结构类型,这三个域分别是:MPI_SOURCE、MPI_TAG和MPI_ERROR)MPI_RECV从指定的进程source接收消息,并且该消息的数据类型和消息标识和本接收进程的datatype和tag相一致,接收到的消息所包含的数据元素的个数最多不能超过count。2020/2/615MPI预定义数据类型MPI预定义类型与C数据类型对应关系MPI预定义数据类型相应的C数据类型MPI_CHARsignedcharMPI_SHORTsignedshortintMPI_INTsignedintMPI_LONGsignedlongintMPI_UNSIGNED_CHARunsignedcharMPI_UNSIGNED_SHORTunsignedshortintMPI_UNSIGNEDunsignedintMPI_UNSIGNED_LONGunsignedlongintMPI_FLOATfloatMPI_DOUBLEdoubleMPI_LONG_DOUBLElongdoubleMPI_BYTE无对应类型MPI_PACKED无对应类型2020/2/616一般的MPI程序设计流程图MPI_Init()MPI_Comm_rank()MPI_Comm_size()建立新的通信器、定义新的数据类型和进程拓扑结构应用程序实体:计算控制程序体;进程间通信;MPI_Finalize()退出MPI系统程序参数说明End2020/2/617一个简单的发送和接收的例子首先输出几个进程分别运行在哪一台机子.这里调用一个MPI_Get_processor_name获得本机的名字.接着进程0向其他进程发送问候信息,其他进程接收进程0的消息.并输出这一过程.2020/2/618#includempi.h#includeiostream.h#includestring.hvoidmain(intargc,char**argv){charmessage[20];inti,myid,numprocs;intnamelen;MPI_Statusstatus;charprocessor_name[MPI_MAX_PROCESSOR_NAME];MPI_Init(&argc,&argv);MPI_Comm_size(MPI_COMM_WORLD,&numprocs);MPI_Comm_rank(MPI_COMM_WORLD,&myid);MPI_Get_processor_name(processor_name,&namelen);coutHelloWorld!processmyidofnumprocsonprocessor_nameendl;if(myid==0){strcpy(message,“Hello,World!);for(i=1;inumprocs;i++){MPI_Send(message,strlen(message),MPI_CHAR,i,99,MPI_COMM_WORLD);coutprocess0sendmessagetoprocessmyidendl;}}else{MPI_Recv(message,20,MPI_CHAR,MPI_ANY_SOURCE,0,MPI_COMM_WORLD,&status);coutprocessmyidrecvivedmessagefromprocess0endl;}MPI_Finalize();}2020/2/619开启4个进程运行结果:2020/2/620开启6个进程运行结果:2020/2/621MPI并行程序的两种基本模式两种最基本的并行程序设计模式:对等模式:各个部分地位相同,功能和代码基本一致,只不过是处理的数据或对象不同,也容易用同样的程序来实现。(典型应用如Jacobi迭代)主从模式:具有主进程和从进程,主进程接收从进程的处理结果,并进行汇总处理(典型应用如矩阵向量乘法)2020/2/622对等模式—并行jacobi程序这里的jacobi迭代是计算一个矩阵的数据二维数组A(M,M)。其边界值边界赋为8,内部初值为0,通过迭代求矩阵各点的值.假设需要迭代的数据是M*M的二维数组A(M,M),令M=4*N,按上图进行数据划分,则分布在4个不同进程上的数据分别是:进程0:A(M,1:N);进程1:A(M,N+1:2*N);进程2:A(M,2*N+1:3*N);进程3:A(M,3*N+1:4*N).由于在迭代过程中,边界点新值的计算需要相邻边界其他块的数据,因此在每一个数据块的两侧各增加1列的数据空间,用于存放从相邻数据块通信得到的数据。每个数据块的大小就从M*N扩大到M*(N+2)。2020/2/623为了并行求解,这里将参加迭代的数据按列进行分割,假设有4个进程同时并行计算,数据的分割结果如图:边界点新值的计算需要相邻边界其他块的数据,因此在每一个数据块的两侧各增加1列进程0进程1进程2进程3按列划分2020/2/624进程0进程1进程2进程3发送发送发送发送发送发送接收接收接收接收接收接收2020/2/625例子:并行jacobi程序programmaininclude‘mpif.h’integertotalsize,mysize,stepsParameter(totalsize=16)(定义全局数组的规模)parameter(mysize=totalsize/4,steps=10)integern,myid,numprocs,i,j,rcReala(totalsize,mysize+2),b(totalsize,mysize+2)Integerbegin_col,end_col,ierrIntegerstatus(MPI_STATUS_SIZE)callMPI_INIT(ierr)callMPI_COMM_RANK(MPI_COMM_WORLD,myid,ierr)callMPI_COMM_SIZE(MPI_COMM_WORLD,numprocs,ierr)print*,”Pr