并行程序设计---MPIOpenmp2015-12-15报告人:方宝辉Contents(目录)1.什么是MPI,openmp2.适合什么体系结构3.怎样并行编程4.结论MPI与Openmp对比OpenMP:线程级(并行粒度);共享存储;隐式(数据分配方式);可扩展性差;MPI:进程级;分布式存储;显式;可扩展性好。OpenMP采用共享存储,意味着它只适应于SMP,DSM机器,不适合于集群。MPI虽适合于各种机器,但它的编程模型复杂:需要分析及划分应用程序问题,并将问题映射到分布式进程集合;需要解决通信延迟大和负载不平衡两个主要问题;调试MPI程序麻烦;MPI程序可靠性差,一个进程出问题,整个程序将错误;其中第2个问题感受深刻。每次听我们部门并行组的人做报告,总是听到他们在攻克通信延迟大和负载不平衡的问题。一种并行算法的好坏就看它有没有很好的解决这两个问题。附:SMP(Symmetricmulti-processing),共享总线与内存,单一操作系统映象。在软件上是可扩展的,而硬件上不能。DSM(distributedsharedmemory),SMP的扩展。物理上分布存储;单一内存地址空间;非一致内存访问;单一操作系统映象。SMP(对称多处理机)SMP(SymmetricMulti-Processing),对称多处理结构的简称,是指在一个计算机上汇集了一组处理器(多CPU),各CPU之间共享内存子系统以及总线结构。在这种技术的支持下,一个服务器系统可以同时运行多个处理器,并共享内存和其他的主机资源。P/CP/CSMSM互连系统。。。P/C:微处理器和高速缓存SM:共享存储器SMDSM分布共享内存DSM(distributedsharedmemory),SMP的扩展。物理上分布存储;单一内存地址空间;非一致内存访问;单一操作系统映象。分布式共享内存,它使得不同机器上的进程不用通过共享物理内存就可以使用共享数据,DSM是一个共享内存的程序模型,它在某些方面优于消息的模型。定制网络P/CLMDIRNICP/CLMDIRNICMBMB。。。。P/C微处理器和高速缓存LM本地磁盘DIR高速缓存目录NIC网络接口电路DSM分布共享内存DSM和SMP主要差别在于,在DSM中存储器是物理地分布在不同结点中的。但系统硬件和软件为用户建立了一个单地址空间的幻觉。P/CP/CSMSM互连系统。。。定制网络P/CLMDIRNICP/CLMDIRNICMBMB。。。集群系统(cluster)机群(cluster)系统是互相连接的多个独立计算机的集合,这些计算机可以是单机或多处理器系统(PC、工作站或SMP),每个结点都有自己的存储器、I/O设备和操作系统。机群对用户和应用来说是一个单一的系统,它可以提供低价高效的高性能环境和快速可靠的服务。编程环境和应用可用性和单一的系统映像基础设施OS结点OS结点OS结点。。。。。商品化或专用互联网什么是MPI?•MassagePassingInterface:是消息传递函数库的标准规范,由MPI论坛开发,支持Fortran和C•一种新的库描述,不是一种语言。共有上百个函数调用接口,在Fortran和C语言中可以直接对这些函数进行调用•MPI是一种标准或规范的代表,而不是特指某一个对它的具体实现•MPI是一种消息传递编程模型,并成为这种编程模型的代表和事实上的标准最基本的MPIMPI调用借口的总数虽然庞大,但根据实际编写MPI的经验,常用的MPI调用的个数确什么有限。下面是6个最基本的MPI函数。1.MPI_Init(…);2.MPI_Comm_size(…);3.MPI_Comm_rank(…);4.MPI_Send(…);5.MPI_Recv(…);6.MPI_Finalize();MPI初始化-MPI_INITintMPI_Init(int*argc,char**argv)MPI_INIT(IERROR)•MPI_INIT是MPI程序的第一个调用,它完成MPI程序的所有初始化工作。所有的MPI程序的第一条可执行语句都是这条语句。•启动MPI环境,标志并行代码的开始.•并行代码之前,第一个mpi函数(除MPI_Initialize()外).•要求main必须带参数运行,否则出错.MPI结束-MPI_FINALIZEintMPI_Finalize(void)MPI_FINALIZE(IERROR)•MPI_FINALIZE是MPI程序的最后一个调用,它结束MPI程序的运行,它是MPI程序的最后一条可执行语句,否则程序的运行结果是不可预知的。•标志并行代码的结束,结束除主进程外其它进程.•之后串行代码仍可在主进程(rank=0)上运行(如果必须).:开始写MPI并行程序•MPI提供了下列函数来回答这些问题:•用MPI_Comm_size获得进程个数pintMPI_Comm_size(MPI_Commcomm,int*size);•用MPI_Comm_rank获得进程的一个叫rank的值,该rank值为0到p-1间的整数,相当于进程的IDintMPI_Comm_rank(MPI_Commcomm,int*rank);有消息传递Greeting进程0rank=0..Send()...进程1rank=1进程2rank=2进程3rank=3..Send().....Send().....Recv()...greetings(c)#includestdio.h#includempi.hmain(intargc,char*argv[]){intnumprocs,myid,source;MPI_Statusstatus;charmessage[100];MPI_Init(&argc,&argv);MPI_Comm_rank(MPI_COMM_WORLD,&myid);MPI_Comm_size(MPI_COMM_WORLD,&numprocs);有消息传递greetings(c)if(myid!=0){strcpy(message,HelloWorld!);MPI_Send(message,strlen(message)+1,MPI_CHAR,0,99,MPI_COMM_WORLD);}else{/*myid==0*/for(source=1;sourcenumprocs;source++){MPI_Recv(message,100,MPI_CHAR,source,99,MPI_COMM_WORLD,&status);printf(%s\n,message);}}MPI_Finalize();}/*endmain*/通信因子(comm)和标识符(tag)通信因子(comm),包含源与目的进程的一组上下文相关的进程集合,除非用户自己定义(创建)了新的通信因子,否则一般使用系统预先定义的全局通信因子MPI_COMM_WORLDMPI_Send(buf,count,datatype,dest,tag,comm,ierr)MPI_Recv(buf,count,datatype,source,tag,comm,status,ierr)标识符tag,由程序员指定为标识一个消息的唯一非负整数值(0-32767),发送操作和接收操作的标识符一定要匹配,但对于接收操作来说,如果tag指定为MPI_ANY_TAG则可与任何发送操作的tag相匹配。阻塞与非阻塞的差别•用户发送缓冲区的重用:•非阻塞的发送:仅当调用了有关结束该发送的语句后才能重用发送缓冲区,否则将导致错误;对于接收方,与此相同,仅当确认该接收请求已完成后才能使用。所以对于非阻塞操作,要先调用等待MPI_Wait()或测试MPI_Test()函数来结束或判断该请求,然后再向缓冲区中写入新内容或读取新内容。•阻塞发送将发生阻塞,直到通讯完成.•非阻塞可将通讯交由后台处理,通信与计算可重叠.•发送语句的前缀由MPI_改为MPI_I,I:immediate:•标准模式:MPI_Send(…)-MPI_Isend(…)•Buffer模式:MPI_Bsend(…)-MPI_Ibsend(…)•…非阻塞标准发送和接收通信的完成(常用于非阻塞通信)•发送的完成:代表发送缓冲区中的数据已送出,发送缓冲区可以重用。它并不代表数据已被接收方接收。数据有可能被缓冲;•接收的完成:代表数据已经写入接收缓冲区。接收者可访问接收缓冲区。•通过MPI_Wait()和MPI_Test()来判断通信是否已经完成;intp,myrank;floatbuf;MPI_Commcomm;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);Broadcast--数据广播databuf..MPI_Bcast();.data..MPI_Bcast();.data..MPI_Bcast();.Process0myrank=0Process1myrank=1Processp-1myrank=p-1intMPI_Bcast(void*buffer,/*发送/接收buf*/intcount,/*元素个数*/MPI_Datatypedatatype,introot,/*指定根进程*/MPI_Commcomm)根进程既是发送缓冲区也是接收缓冲区Broadcast注意事项intp,myrank,N,i;floatbuf;MPI_Commcomm;MPI_Init(&argc,&argv);/*得进程编号*/MPI_Comm_rank(comm,&my_rank);/*得进程总数*/MPI_Comm_size(comm,&p);for(i=1,N,i++){if((i%p-1)==my_rank){buf=1.0;MPI_Bcast(&buf,1,MPI_FLOAT,0,comm);}}这是错误的!!MPI程序一(C版)#includestdio.h#includempi.hmain(intargc,char*argv[]){intmyid,numprocs;MPI_Init(&argc,&argv);MPI_Comm_rank(MPI_COMM_WORLD,&myid);MPI_Comm_size(MPI_COMM_WORLD,&numprocs);printf(“Iam%dof%d\n,myid,numprocs);MPI_Finalize();}MPI程序一(Fortran版)programmaininclude‘mpif.h’integerierr,myid,numprocscallMPI_INIT(ierr)callMPI_COMM_RANK(MPI_COMM_WORLD,myid,ierr)callMPI_COMM_SIZE(MPI_COMM_WORLD,numprocs,ierr)print*,‘Iam',myid,‘of',numprocscallMPI_FINALIZE(ierr)end•[dair@node01~]$mpicc–ohello1hello1.c•[dair@node01~]$mpirun-np4hello1Iam0of4Iam1of4Iam2of4Iam3of4•[dair@node01~]$:运行结果OpenMP简介OpenMP是基于共享存储体系结构的一个并行编程标准。OpenMP通过在源代码(串行程序)中添加OpenMP指令和调用OpenMP库函数来实现在共享内存系统上的并行执行。OpenMP为共享内存并行程序员提供了一种简单灵活的开发并行应用的接口模型,使程序既可以在台式机上执行,也可以在超级计算机上执行,具有良好的可移植性不打开OpenMP编译选项,编译器将忽略OpenMP指令,从而生成串行可执行程序打开OpenMP编译选