《并行程序设计导论课件》由会员分享,可在线阅读,更多相关《并行程序设计导论课件(70页珍藏版)》请在金锄头文库上搜索。
1、Message Passing ProgrammingLi XiSchool of Information Science & EngineeringCentral South University消息传递编程消息传递编程 主要介绍采用主要介绍采用2个非专利的、广为接受的消息传递个非专利的、广为接受的消息传递系统系统 PVM和和MPI的设计思想和功能特点,以及借助其的设计思想和功能特点,以及借助其实现并行处理的一般过程。实现并行处理的一般过程。 MPI: Massage Passing Interface PVM: Parallel Virtual Machine (http:/lib.org
2、/pvm3/index.html)消息传递范例消息传递范例 介绍开发分布式并行性的消息传递方法所具介绍开发分布式并行性的消息传递方法所具有的特征。有的特征。消息传递软件包消息传递软件包 研究并推出的基于消息传递的软件包较多,研究并推出的基于消息传递的软件包较多,其中包括专有软件和非专利软件。目前,大多数其中包括专有软件和非专利软件。目前,大多数并行计算机供应商已将最流行的并行计算机供应商已将最流行的PVM和和MPI作为作为对消息传递的自然支持。对消息传递的自然支持。PVM and MPIMPI : 是由是由MPI论坛开发的有关函数库的标准论坛开发的有关函数库的标准规范,通过提供一个独立于平台的
3、消息传递规范,通过提供一个独立于平台的消息传递库达到其可移植性的目的。库达到其可移植性的目的。PVM: 是一个软件系统,主要功能是将网络上是一个软件系统,主要功能是将网络上各种各种同构同构或或异构异构的计算机利用起来,给用户的计算机利用起来,给用户提供一个统一的、灵活的并行计算资源。已提供一个统一的、灵活的并行计算资源。已被移植到被移植到SMP、PVP、MPP、COW和和PC上。上。 两者都提供与两者都提供与Fortran和和C的捆绑。的捆绑。Massage-Passing Modes通信:通信: 表示消息传递系统中所有交互操作,包括:表示消息传递系统中所有交互操作,包括: 通信通信_Comm
4、unication 同步同步_Synchronization 聚集聚集_Aggregation 一般地,通信在同组进程间进行,通信进一般地,通信在同组进程间进行,通信进程需要了解的内容有:程需要了解的内容有: 参与通信的进程数;参与通信的进程数; 采用何种方式保证进程间的同步;采用何种方式保证进程间的同步; 如何管理通信缓冲区;如何管理通信缓冲区;例例: 消息传递中的发送和接收缓冲区消息传递中的发送和接收缓冲区进程P M=10; L1: send M to Q; L2: M=20; goto L1;进程Q S=-100; L1: receive S from P; L2: X=S+1;发送缓冲
5、区发送缓冲区接收缓冲区接收缓冲区说明:说明:同步和锁定方式中,代码执行后同步和锁定方式中,代码执行后X的值为的值为11; 非锁定方式中,代码执行后非锁定方式中,代码执行后X的值的值可能可能为为11、21或或-99。消息传递系统中的通信方式消息传递系统中的通信方式同步消息传递:同步消息传递:Synchronous Message Passing 发送发送/接收进程必须等待发送接收进程必须等待发送/接收后才能返回。接收后才能返回。锁定发送锁定发送/接收:接收:Blocking Send/Receive 锁定发送时,发送进程只有等待消息发送返回后才锁定发送时,发送进程只有等待消息发送返回后才能继续。
6、需要能继续。需要临时缓冲区临时缓冲区暂存消息。暂存消息。非锁定发送非锁定发送/接收:接收:NonBlocking Send/Receive 非锁定发送时,发送进程通知系统消息非锁定发送时,发送进程通知系统消息M已经发出已经发出后即可返回,此时消息后即可返回,此时消息M并不一定已经离开并不一定已经离开M,因此重,因此重写写M是不安全的。可能需要一个是不安全的。可能需要一个临时缓冲区临时缓冲区三种通信方式比较三种通信方式比较三种通信方式比较三种通信方式比较(续续)同步方式:同步方式: 优点:优点:清晰、可靠;无需系统临时缓冲区;清晰、可靠;无需系统临时缓冲区; 缺点:缺点:发送方和接收方互为等待,
7、导致周期浪费。发送方和接收方互为等待,导致周期浪费。异步方式:异步方式:该方式几乎存在于所有消息传递系统中。该方式几乎存在于所有消息传递系统中。 优点:优点:无周期浪费(等待时间少);无周期浪费(等待时间少); 缺点:缺点:需设缓冲,且无法知道缓冲区应设大小;需设缓冲,且无法知道缓冲区应设大小; 导致结果的不确定性;导致结果的不确定性; 为正确接收,需附加状态检测或等待函数;为正确接收,需附加状态检测或等待函数; 需要管理缓冲区,导致系统消耗需要管理缓冲区,导致系统消耗(Overhead)。 采用何种算法、机制,如何更有效地采用何种算法、机制,如何更有效地隐藏通信时延隐藏通信时延,是异步方式是
8、异步方式研究内容之一研究内容之一。下页例下页例通过等待函数保证消息安全接收通过等待函数保证消息安全接收进程P M=10; L1: send M to Q; 某些不改变Q的计算; Wait for M to be sent; L2: M=20; goto L1;进程Q S=-100; Receive S from P; 某些不使用S的计算; Wait for S to be received; X=S+1;Massage Passing Interface MPI MPI是消息传递函数库的标准规范,是消息传递函数库的标准规范,9494年公年公布,布,9797年推出年推出MPI-2MPI-2的修订
9、版,增加了动态进程、的修订版,增加了动态进程、非阻塞消息等功能。非阻塞消息等功能。 MPI MPI已经在已经在WindowsWindows、UnixUnix及主要的并行计及主要的并行计算机上得到实现,所以,对于用标准算机上得到实现,所以,对于用标准C/FortranC/Fortran编程、使用编程、使用MPIMPI进行消息传递的程序,可不加改进行消息传递的程序,可不加改变地在变地在PCPC、工作站、工作站网络、工作站、工作站网络、MPPMPP和任何和任何OSOS上执行。上执行。MPI功能设计基础功能设计基础MPI功能设计,基于功能设计,基于4个正交的概念:个正交的概念: Massage Dat
10、a Types (消息数据类型)(消息数据类型) Communicator (通信子)(通信子) Communication Operation(通信操作)(通信操作) Virtual Topology (虚拟拓扑)(虚拟拓扑)其中,前其中,前3个是最基本、最常用的,主要讨论。个是最基本、最常用的,主要讨论。 MPI提供了提供了200多个多个函数,由于正交性设计,函数,由于正交性设计,使其较使其较PVM更容易学习、使用。更容易学习、使用。MPI并行性讨论并行性讨论 MPI MPI假设进程是静态的,即所有并行进程在假设进程是静态的,即所有并行进程在装入时被创建,直到程序结束。装入时被创建,直到程
11、序结束。 MPI MPI设置一个由所有进程组成的缺省进程组,设置一个由所有进程组成的缺省进程组,组标识为组标识为MPI_COMM_WORLDMPI_COMM_WORLD。 MPI MPI由由6 6个函数构成编写完整消息传递程序的个函数构成编写完整消息传递程序的最小集:最小集:MPI_Comm_Size; MPI_Comm_rank;MPI_Comm_Size; MPI_Comm_rank; MPI_Send; MPI_Recv; MPI_Send; MPI_Recv; MPI_Init; MPI_Finalize; MPI_Init; MPI_Finalize;缺省组大小缺省组大小每个进程秩每
12、个进程秩终止终止MPI环境环境MPI消息传递程序示例消息传递程序示例例:一个例:一个SPMDSPMD类型的计算类型的计算foo(i)foo(i)的消息传递程序。的消息传递程序。foo(i)foo(i)说明:说明: 设共有设共有N N个整数,个整数,foo(i)foo(i)完成完成i*ii*i操作,最后操作,最后汇总;汇总;假设有假设有n n个结点并行处理,则一般处理方案为:个结点并行处理,则一般处理方案为:n=3n=3时时 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 . . . N . . . N进程进程0 0处理:处理:foo(0)+foo(n)+foo(
13、2*n)+. .foo(0)+foo(n)+foo(2*n)+. .进程进程k(0kn)k(0kn)处理:处理:foo(k)+foo(n+k)+foo(2*n+k)+.foo(k)+foo(n+k)+foo(2*n+k)+.各进程处理结果发送到各进程处理结果发送到0 0进程,由其完成最后汇总进程,由其完成最后汇总。SPMD类型的类型的MPI程序程序 myprog.c#include “mpi.h”int foo int i; main(argc,argv)int argc;char *argv ; int i, tmp, sum=0, group_size,my_rank,N; MPI_Ini
14、t(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&group_size); MPI_Comm_rank(MPI_COMM_WORLD,&my_rank); if (my_rank=0) printf(“Enter N:”); scanf(“%d”,&N); for (i=1;igroup_size;i+) MPI_send(&N,1,MPI_INT,i,i,MPI_COMM_WORLD); for (i=my_rank;iN;i=i+group_size ) sum=sum+foo(i); for (i=1;igroup_size;i+) MPI_Re
15、cv(&tmp,1,MPI_INT,i,i,MPI_COMM_WORLD,&status); sum=sum+tmp; printf(“n The result=%d”,sum); else MPI_Recv(&N,1,MPI_INT,0,i,MPI_COMM_WORLD,&status); for (i=my_rank;iN;i=i+group_size ) sum=sum+foo(i); MPI_Send(&sum,1,MPI_INT,0,i,MPI_COMM_WORLD); MPI_Finalize();消息标志消息标志目的进程目的进程结构指针结构指针源进程源进程程序程序myprog.c
16、执行说明执行说明1 用并行编译器用并行编译器mpicc编译;编译; mpicc myprog.c -o myprog2 将可执行文件装到将可执行文件装到n个结点上运行;个结点上运行; MPIRUN -np n myprog3 每个结点执行相同的程序代码,构成每个结点执行相同的程序代码,构成SPMD方式。方式。MPI Messages MPI中进程的地址空间相互分离,一中进程的地址空间相互分离,一个进程不能访问另一个地址空间中的数个进程不能访问另一个地址空间中的数据,所以通信采用消息传递方式完成。据,所以通信采用消息传递方式完成。 消息一般由消息头消息一般由消息头(Head)及消息正及消息正文文
17、(Text)组成。组成。MPI中消息发送中消息发送/接收语句格式接收语句格式 MPI_Send(address,count,datatype, destination,tag,communicator) MPI_Recv(address,count,datatype, source,tag,communicator,status)例如:将数组例如:将数组double A100发送发送 MPI_Send(A,100,MPI_DOUBLE,DEST,.); MPI_Recv(B,100,MPI_DOUBLE,source,.);发送发送A2,A3: MPI_Send(A+16,2,MPI_DOUB
18、LE,DEST,.)如何发送如何发送A中下标为偶数的元素?中下标为偶数的元素?双精度每项双精度每项8字节字节MPI设置数据类型的原因设置数据类型的原因支持异构计算;支持异构计算;便于从发送缓冲区中非连续、非均匀地取数据。便于从发送缓冲区中非连续、非均匀地取数据。例例: : 发送不同类型的数据发送不同类型的数据 将字符串将字符串char String1000char String1000的前的前100100个字符从洛杉矶个字符从洛杉矶的一台工作站发送到北京的一台工作站,若用如下格式:的一台工作站发送到北京的一台工作站,若用如下格式: USA: send(String,100,China); Ch
19、ina: recv(String,100,USA); 两地的字符表示长度不同:两地的字符表示长度不同:1/21/2字节,导致结果不正确。字节,导致结果不正确。改进:改进:USA: MPI_Send(String,100,MPI_CHAR,China); China: MPI_Recv(String,100,MPI_CHAR,USA); MPI_CHARMPI_CHAR在美国在美国/ /中国分别以中国分别以8/168/16位实现,接收时转换。位实现,接收时转换。类型为类型为MPI_CHAR的数据项数的数据项数MPI附加数据类型附加数据类型 MPI MPI包括包括C/FortranC/Fortra
20、n所有基本数据类型,并增加所有基本数据类型,并增加2 2个附加个附加类型:类型:MPI_BYTEMPI_BYTE和和MPI_PACKEDMPI_PACKED。例例: : 利用附加类型完成利用附加类型完成A100A100中偶数元素发送中偶数元素发送 double A100; MPI_Pack_size(50,MPI_DOUBLE,comm,&BufferSize); TempBuffer=malloc(BufferSize); j=sizeof(MPI_DOUBLE); Position=0; for (i=0;i50;i+) MPI_Pack(A+i*j,1,MPI_DOUBLE,TempBu
21、ffer, Buffersize,&Position,comm); MPI_Send(TempBuffer,Position,MPI_PACKED,dest,.);确定打包缓冲区大小确定打包缓冲区大小缓冲区大小返回值缓冲区大小返回值打包项打包项计数计数MPI派生数据类型派生数据类型例例: :发送一个数组中的所有偶数项元素发送一个数组中的所有偶数项元素 double A100 MPI_Data_type EvenElements; MPI_Type_vector(50,1,2,MPI_DOUBLE,&EvenElements); MPI_Type_commit(&EvenElements); M
22、PI_Send(A,1,EvenElements,destination, );说明:说明:MPI_Type_vector (count,blocklength,stride,oldtype,&newtype)派生数据项数派生数据项数按按oldtype的每块长度的每块长度块间跨度块间跨度MPI数据类型数据类型Massage Buffer 消息缓冲区由系统或程序员说明,用于暂存收发消息缓冲区由系统或程序员说明,用于暂存收发的消息数据值。消息缓冲可以是如下的消息数据值。消息缓冲可以是如下3 3种之一:种之一: 用户说明的一个消息变量地址;用户说明的一个消息变量地址; 系统创建管理的一个暂存消息区;
23、系统创建管理的一个暂存消息区; 用户创建管理的一个暂存消息区;用户创建管理的一个暂存消息区;3种缓冲区类型示意种缓冲区类型示意 进程进程P P 进程进程Q Qdouble A100; double B32; MPI_Send(A,32,MPI_DOUBLE,Q,.); MPI_Recv(B,32,MPI_DOUBLE,P,); 进程进程PAMM进程进程QB进程进程QB进程进程PAMMS进程进程QB进程进程PAMMT优点:优点:消息在消息在2进程间直接同步传递;进程间直接同步传递;缺点:缺点:接收进程缓冲区容量应足够大;接收进程缓冲区容量应足够大;优点:优点:支持异步通信;支持异步通信;缺点:缺
24、点:使用缓冲区增加系统消耗;使用缓冲区增加系统消耗; 若系统缓冲若系统缓冲S太大,可能异常;太大,可能异常; 缺点:缺点:若系统不能容纳缓冲区若系统不能容纳缓冲区T,将,将产生错误消息通知应用程序,产生错误消息通知应用程序,并体面终止。并体面终止。Message Envelope in MPI 消息信封表示一个接收者的信息,消息信封表示一个接收者的信息,MPI中由中由3部分组成:部分组成:destination、tag和和communicator。 消息标志消息标志tag: 整数,标识不同类型消息并整数,标识不同类型消息并限定消息接收。设置原因:限定消息接收。设置原因: 避免消息后发先至,造成
25、接收错误;避免消息后发先至,造成接收错误; 服务进程通过判定消息标志,可完成相应服务进程通过判定消息标志,可完成相应处理。处理。消息标志使用示例消息标志使用示例Process P: send(request1,32,Q,tag1);Process R: send(request2,32,Q,tag2);Process Q: while(true) recv(received_request, Any_Process,32,Any_tag,Status); if (Status.Tag=tag1) process received_request in one way; if (Status.T
26、ag=tag2) process received_request in another way; 通配进程通配进程ID通配标志通配标志MPI_Statustypedef struct MPI_Status int count; int cancelled; int MPI_SOURCE; int MPI_TAG; int MPI_ERROR; MPI_Status;n消息状态 status status (MPI_Status 类型)存放接收消息的状态信息,包括消息的源进程标识、消息标签、包含的数据项个数等。n它是消息接收函数MPI_Recv的最后一个参数n当一个接收者从不同进程接收不同大小
27、和不同标签的消息时,消息的状态信息非常有用。 Communicator 通信子由进程组和一个现场组成。通信子由进程组和一个现场组成。 进程组是进程的有限和定序集,有限是指进进程组是进程的有限和定序集,有限是指进程组由有限个进程程组由有限个进程n n组成,组成,n n为组的大小。定序指为组的大小。定序指n n个进程在进程组中的排序值,即个进程在进程组中的排序值,即进程进程IDID。相关例程:相关例程: MPI_Comm_size(communicator,&group_size) MPI_Comm_rank(communicator,&my_rank) 一个进程组可以有多个通信子;不同通信子一个
28、进程组可以有多个通信子;不同通信子可包含不同进程。可包含不同进程。设置通信子好处设置通信子好处 不同通信子中通信分离;不同通信子中通信分离; 同一通信子中集合通信与点同一通信子中集合通信与点-点通信分离。点通信分离。 每个通信子都有一个不同现场,每个通信子都有一个不同现场,MPI一个现一个现场中传递的消息不会在另一个现场中被接收,避场中传递的消息不会在另一个现场中被接收,避免了通信子间的干扰,达到通信过程的安全分离。免了通信子间的干扰,达到通信过程的安全分离。通信子参数:通信子参数: intra-communicators 组内通信组内通信(缺省值缺省值) inter-communicator
29、s 组间通信组间通信通信子管理通信子管理 MPI预定义通信子:预定义通信子:MPI_COMM_WORLD包含包含所有进程集。用户可通过所有进程集。用户可通过MPI提供的多个相关例提供的多个相关例程定义自己的通信子,下列为其中程定义自己的通信子,下列为其中2个:个: MPI_Comm_dup(communicators,&new_comm)功能:功能:将通信子将通信子communicators中的进程复制到中的进程复制到new_comm通信子中。通信子中。 MPI_Comm_split()功能:功能:将一个通信子中的进程按参数要求,分解将一个通信子中的进程按参数要求,分解到多个新的通信子中。到多
30、个新的通信子中。构造用户定义通信子示例构造用户定义通信子示例MPI_Comm MyWorld,SplitWorld;int my_rank,group_size,Color,Key;MPI_init(&argc,&argv);MPI_Comm_dup(MPI_COMM_WORLD,&MyWorld);MPI_Comm_rank(MyWorld,&my_rank);MPI_Comm_size(MyWorld,&group_size);Color=my_rank % 3;Key=my_rank/3MPI_Comm_split(MyWorld,Color,Key,&SplitWorld);按颜色分组
31、按颜色分组组内按组内按Key排序排序通信子通信子MyWorld分裂结果分裂结果Message-Passing Codeto Compute #define N 1000000Main() double local, pi,w; long i,taskid,numtask; w=1.0/N; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&taskid); MPI_Comm_size(MPI_COMM_WORLD,&numtask); forall (i=taskid; iN; i=i+numtask) local=(i+0.5)*w;
32、local=4.0/(1.0+local*local); MPI_Reduce(&local,&pi,1,MPI_Double,MPI_SUM,0, MPI_COMM_WORLD); if (taskid=0) printf(“pi is %fn”, pi*w); MPI_Finalize(); Different Send/Receive Operations in MPI Example:Process Pipeline Using Message Passing n3进程流水线,每个进程连续地接收来自左边的输入进程流水线,每个进程连续地接收来自左边的输入数据流;计算一个新数据流,发送给右
33、边进程。数据流;计算一个新数据流,发送给右边进程。X=P(W)Y=Q(X)Z=R(Y)WXYZProcess Q: While (Not_Done) MPI_Irecv(NextX,); MPI_Isend(PreviousY,); CurrentY=Q(CurrentX); ConcurrentExample(Cont)nA well-known double-buffering schemeXBuf0 XBuf1 YBuf0 YBuf1 Y=Q(X)Receive XSend YExample(Code)Process Q: While (Not_Done) if(X=XBuf0) X=X
34、Buf1;Y=YBuf1;Xin=XBuf0;Yout=YBuf0; else X=XBuf0;Y=YBuf0;Xin=XBuf1;Yout=YBuf1; MPI_Irecv(Xin,recv_handle); MPI_Isend(Yout,send_handle); Y=Q(X); /*overlapping computation*/ MPI_Wait(recv_handle,recv_ststus); MPI_Wait(send_handle,send_status); send_handle, recv_handle用于发送用于发送/接收是否结束判断。接收是否结束判断。 MPI_Wai
35、t(Handle,Status): 等待直到等待直到Handle指明的发送接收结指明的发送接收结束,并将某些状态信息传给束,并将某些状态信息传给Status.接送区指针接送区指针发送区指针发送区指针Collective Communicationn群集通信(Collective Communications)是一个进程组中的所有进程都参加的全局通信操作。 n群集通信一般实现三个功能:通信、聚集和同步。 n通信(communication)主要完成组内数据的传输 n聚集(aggregation)在通信的基础上对给定的数据完成一定的操作 n同步(synchronization)实现组内所有进程在执
36、行进度上取得一致 Collective Communicationn群集通信(CommunicationCommunication),按照通信方向的不同,又可以分为三种:一对多通信,多对一通信和多对多通信。 n一对多通信一对多通信:一个进程向其它所有的进程发送消息,这个负责发送消息的进程叫做Root进程。n多对一通信多对一通信:一个进程负责从其它所有的进程接收消息,这个接收的进程也叫做Root进程。 n多对多通信多对多通信:每一个进程都向其它所有的进程发送或者接收消息。Collective CommunicationCollective Communicationn广播(广播(broadcas
37、t)是一对多通信的典型例子,其调用格式如下:nMPI_Bcast(Address, Count, Datatype, Root, Comm)nBroadcast的特点的特点n标号为Root的进程发送相同的消息给通信域Comm中的所有进程。n消息的内容如同点对点通信一样由三元组标识。n对Root进程来说,这个三元组既定义了发送缓冲也定义了接收缓冲。对其它进程来说,这个三元组只定义了接收缓冲 Collective Communication#include #include mpi.hint main(int argc, char *argv ) int rank, value; MPI_Init
38、( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); do if (rank = 0) /*进程进程0读入需要广播的数据读入需要广播的数据*/ scanf( %d, &value ); MPI_Bcast( &value, 1, MPI_INT, 0, MPI_COMM_WORLD ); /*将该数据广播出去将该数据广播出去*/ printf( Process %d got %dn, rank, value ); /*各进程打印收到的数据各进程打印收到的数据*/ while (value = 0); MPI_Finalize();
39、return 0;Broadcast ExampleCollective Communicationn收集(收集(Gather)是多对一通信的典型例子,其调用格式下:MPI_Gather(SendAddress, SendCount, SendDatatype,RecvAddress, RecvCount, RecvDatatype, Root, Comm)nGather的特点n在收集操作中,Root进程从进程域Comm的所有进程(包括它自已)接收消息。n这n个消息按照进程的标识rank排序进行拼接,然后存放在Root进程的接收缓冲中。n接收缓冲由三元组标识,发送缓冲由三元组标识,所有非Roo
40、t进程忽略接收缓冲。Collective CommunicationMPI_Comm comm;int gsize,sendarray100;int root,*rbuf;.MPI_Comm_size(comm, &gsize);rbuf=(int *)malloc(gsize*100*sizeof(int);MPI_Gather(sendarray, 100, MPI_INT, rbuf, 100, MPI_INT, root, comm);Gather Examplen散播(散播(Scatter)也是一个一对多操作,其调用格式如下:MPI_Scatter(SendAddress, Send
41、Count, SendDatatype,RecvAddress, RecvCount, RecvDatatype, Root, Comm)Collective CommunicationnScatter的特点nScatter执行与Gather相反的操作。nRoot进程给所有进程(包括它自已)发送一个不同的消息,这n (n为进程域comm包括的进程个数)个消息在Root进程的发送缓冲区中按进程标识的顺序有序地存放。n每个接收缓冲由三元组标识,所有的非Root进程忽略发送缓冲。对Root进程,发送缓冲由三元组标识。Collective CommunicationMPI_Comm comm;int
42、gsize,*sendbuf;int root, rbuf100;.MPI_Comm_size(comm, &gsize);sendbuf = (int *)malloc(gsize*100*sizeof(int);.MPI_Scatter(sendbuf, 100, MPI_INT, rbuf, 100, MPI_INT, root, comm);Scatter Examplen全局收集(Allgather)多对多通信的典型例子,其调用格式如下:MPI_Allgather(SendAddress, SendCount, SendDatatype,RecvAddress, RecvCount,
43、 RecvDatatype, Comm)nAllgather操作相当于每个进程都作为ROOT进程执行了一次Gather调用,即每一个进程都按照Gather的方式收集来自所有进程(包括自己)的数据。 Collective CommunicationMPI_Comm comm;int gsize,sendarray100;int *rbuf;.MPI_Comm_size(comm, &gsize);rbuf = (int *)malloc(gsize*100*sizeof(int);MPI_Allgather(sendarray, 100, MPI_INT, rbuf, 100, MPI_INT,
44、 comm);Allgather Examplen全局交换(Alltoall)也是一个多对多操作,其调用格式如下:MPI_Alltoall(SendAddress, SendCount, SendDatatype,RecvAddress, RecvCount, RecvDatatype, Comm)Collective CommunicationnAlltoall的特点n在全局交换中,每个进程发送一个消息给所有进程(包括它自已)。n这n (n为进程域comm包括的进程个数)个消息在它的发送缓冲中以进程标识的顺序有序地存放。从另一个角度来看这个通信,每个进程都从所有进程接收一个消息,这n个消息以
45、标号的顺序被连接起来,存放在接收缓冲中。n全局交换等价于每个进程作为Root进程执行了一次散播操作。Collective Communication#include mpi.h#include #include #include #include int main(int argc, char * argv ) int rank, size; int chunk = 2; /*发送到一个进程的数据块的大小发送到一个进程的数据块的大小*/ int i,j; int *sb, *rb; int status, gstatus; MPI_Init(&argc,&argv); MPI_Comm_ran
46、k(MPI_COMM_WORLD,&rank); MPI_Comm_size(MPI_COMM_WORLD,&size); sb = (int *)malloc(size*chunk*sizeof(int);/*申请发送缓冲区申请发送缓冲区*/ if ( !sb ) perror( cant allocate send buffer ); MPI_Abort(MPI_COMM_WORLD,EXIT_FAILURE); Alltoall Example rb = (int *)malloc(size*chunk*sizeof(int);/*申请接收缓冲区申请接收缓冲区*/ if ( !rb )
47、perror( cant allocate recv buffer); free(sb); MPI_Abort(MPI_COMM_WORLD,EXIT_FAILURE); for ( i=0 ; i size ; i+ ) for ( j=0 ; j chunk ; j+ ) sbi*chunk+j = rank + i*chunk+j;/*设置发送缓冲区的数据设置发送缓冲区的数据*/ printf(myid=%d, send to id=%d, data%d=%dn, rank, i, j, sbi*chunk+j); rbi*chunk+j = 0;/*将接收缓冲区清将接收缓冲区清0*/
48、/* 执行执行MPI_Alltoall 调用调用*/ MPI_Alltoall(sb,chunk,MPI_INT,rb,chunk,MPI_INT,MPI_COMM_WORLD);Alltoall Example for ( i=0 ; i size ; i+ ) for ( j=0 ; j chunk ; j+ ) printf(myid=%d, recv from id=%d, data%d=%dn, rank, i, j, rbi*chunk+j); /*打印接收缓冲区从其它进程接收的数据打印接收缓冲区从其它进程接收的数据*/ free(sb); free(rb); MPI_Finali
49、ze();Alltoall Examplen同步(SynchronizationSynchronization)功能用来协调各个进程之间的进度和步伐 。目前MPI的实现中支持一个同步操作,即路障同步路障同步路障同步路障同步(Barrier)(Barrier)。n路障同步的调用格式如下:nMPI_Barrier(Comm)n在路障同步操作MPI_Barrier(Comm)中,通信域Comm中的所有进程相互同步。n在该操作调用返回后,可以保证组内所有的进程都已经执行完了调用之前的所有操作,可以开始该调用后的操作。Collective Communication#include mpi.h#incl
50、ude test.h#include #include int main( int argc, char *argv ) int rank, size, i; int *table; int errors=0; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm_size( MPI_COMM_WORLD, &size );Barrier Example /* Make data table */ table = (int *) calloc (size, sizeof(int); tableran
51、k = rank + 1; /*准备要广播的数据准备要广播的数据*/ MPI_Barrier ( MPI_COMM_WORLD ); /* 将数据广播出去将数据广播出去*/ for ( i=0; isize; i+ ) MPI_Bcast( &tablei, 1, MPI_INT, i, MPI_COMM_WORLD ); /* 检查接收到的数据的正确性检查接收到的数据的正确性 */ for ( i=0; isize; i+ ) if (tablei != i+1) errors+; MPI_Barrier ( MPI_COMM_WORLD ); /*检查完毕后执行一次同步检查完毕后执行一次同
52、步*/ . /*其它的计算其它的计算*/ MPI_Finalize();Barrier Examplen群集通信的聚集(AggregationAggregation)功能使得MPI进行通信的同时完成一定的计算。 nMPI聚集的功能分三步实现n首先是通信的功能,即消息根据要求发送到目标进程,目标进程也已经收到了各自需要的消息;n然后是对消息的处理,即执行计算功能;n最后把处理结果放入指定的接收缓冲区。nMPI提供了两种类型的聚集操作: 归约和扫描。 Collective Communicationn归约(Reduce)的调用格式如下:nMPI_Reduce(SendAddress, RecvAd
53、dress, Count, Datatype, Op, Root, Comm)nReduce的特点n归约操作对每个进程的发送缓冲区(SendAddress)中的数据按给定的操作进行运算,并将最终结果存放在Root进程的接收缓冲区(RecvAddress)中。n参与计算操作的数据项的数据类型在Datatype域中定义,归约操作由Op域定义。n归约操作可以是MPI预定义的,也可以是用户自定义的。n归约操作允许每个进程贡献向量值,而不只是标量值,向量的长度由Count定义。Collective CommunicationnMPI预定义的归约操作Collective Communicationn扫描(
54、Scan)的调用格式如下:nMPI_scan(SendAddress, RecvAddress, Count, Datatype, Op, Comm)nscan的特点n可以把扫描操作看作是一种特殊的归约,即每一个进程都对排在它前面的进程进行归约操作。nMPI_SCAN调用的结果是,对于每一个进程i,它对进程0,1,i的发送缓冲区的数据进行了指定的归约操作。n扫描操作也允许每个进程贡献向量值,而不只是标量值。向量的长度由Count定义。Collective Communicationn所有的MPI群集通信操作都具有如下的特点特点:n通信域中的所有进程必须调用群集通信函数。如果只有通信域中的一部分
55、成员调用了群集通信函数而其它没有调用,则是错误的。n除MPI_Barrier以外,每个群集通信函数使用类似于点对点通信中的标准、阻塞的通信模式。也就是说,一个进程一旦结束了它所参与的群集操作就从群集函数中返回,但是并不保证其它进程执行该群集函数已经完成。n一个群集通信操作是不是同步操作取决于实现。MPI要求用户负责保证他的代码无论实现是否同步都必须是正确的。 n所有参与群集操作的进程中,Count和Datatype必须是兼容的。n群集通信中的消息没有消息标签参数,消息信封由通信域和源/目标定义。例如在MPI_Bcast中,消息的源是Root进程,而目标是所有进程(包括Root)。Collect
56、ive CommunicationC+MPI Code to Compute #include mpi.h#include #include double f(double a) return (4.0 / (1.0 + a*a);void main(int argc, char *argv) int done = 0, n, myid, numprocs, i; double PI25DT = 3.141592653589793238462643; double mypi, pi, h, sum, x; double startwtime, endwtime; int namelen; ch
57、ar processor_nameMPI_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);C+MPI Code to Compute fprintf(stderr,Process %d on %sn, myid, processor_name); fflush(stderr); n = 0; while (!
58、done) if (myid = 0) printf(Enter the number of intervals: (0 quits) );fflush(stdout); scanf(%d,&n); startwtime = MPI_Wtime(); MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); if (n = 0) done = 1; else h = 1.0 / (double) n; sum = 0.0; C+MPI Code to Compute for (i = myid + 1; i = n; i += numprocs) x = h
59、* (double)i - 0.5); sum += f(x); mypi = h * sum; MPI_Reduce(&mypi,&pi,1, MPI_DOUBLE, MPI_SUM, 0,MPI_COMM_WORLD); if (myid = 0) printf(pi is approximately %.16f, Error is %.16fn, pi, fabs(pi - PI25DT); endwtime = MPI_Wtime(); printf(wall clock time = %fn, endwtime-startwtime); MPI_Finalize(); Computa
60、tionnIntegration formula of w w1 1o oy yx xSample ProgramA Sequential C Code to Compute #define N=1000000Main() double local, pi=0.0,w; long i; w=1.0/N; for (i=0; iN; i+) local=(i+0.5)*w; pi=pi+4.0/(1.0+local*local); printf(“pi is %fn”, pi*w); Sample ProgramShared-Variable Parallel Codeto Compute #define N 1000000Main() double localN, tempN,pi,w; long i; w=1.0/N; forall (i=0; iN; i+) locali=(i+0.5)*w; tempi=4.0/(1.0+locali*locali); pi=sum(temp); printf(“pi is %fn”, pi*w);