MPI学习笔记
MPI是⼀个跨语⾔的通讯协议,⽤于编写并⾏计算机。⽀持点对点和⼴播。MPI是⼀个信息传递应⽤程序接⼝,包括协议和和语义说明,他们指明其如何在各种实现中发挥其特性。MPI的⽬标是⾼性能,⼤规模性,和可移植性。MPI在今天仍为⾼性能计算的主要模型。
1.MPI初始函数
头⽂件: mpi.h/mpif.h.
int MPI_Init(int *argc, char ***argv)
启动MPI环境,标志并⾏代码的开始.
并⾏代码之前,第⼀个mpi函数(除MPI_Initialize()外).
要求main必须带能运⾏,否则出错.
通信⼦(通信空间): MPI_COMM_WORLD:
⼀个通信空间是⼀个进程组和⼀个上下⽂的组合.上下⽂可看作为组的超级标签,⽤于区分不同的通信⼦.在
执⾏函数MPI_Init之后,⼀个MPI程序的所有进程形成⼀个缺省的组,这个组的通信⼦被写作MPI_COMM_WORLD.该参数是MPI通信操作函数中必不可少的参数,⽤于限定参加通信的进程的范围.
int MPI_Comm_size ( MPI_Comm comm, int *size )
获得通信空间comm中规定的组包含的进程的数量.
指定⼀个communicator,也指定了⼀组共享该空间的进程, 这些进程组成该communicator的group.
int MPI_Comm_rank ( MPI_Comm comm, int *rank )
得到本进程在通信空间中的rank值,即在组中的逻辑编号(从0开始).
int MPI_Finalize()
标志并⾏代码的结束,结束除主进程外其它进程.
之后串⾏代码仍可在主进程(rank = 0)上运⾏(如果必须).
2.点对点通信
1.阻塞通信
1.1 标准通信模式(MPI_Send)
理论上要求接收进程的recv调⽤配合
1.2 缓冲通信模式(MPI_Bsend)
缓冲通信模式主要⽤于解开阻塞通信的发送与接收之间的耦合。有了缓冲机制,即使在接收端没有启动相应的接收的情况下,在完成其消息数据到缓冲区的转移后发送端的阻塞发送函数也可返回。
1.3 就绪通信模式(MPI_Rsend)
仅当对⽅的接收操作启动并准备就绪时,才可发送数据。否则可能导致错误或⽆法预知的结果。
1.4 同步通信模式(MPI_Ssend)
不论接收端是否启动了接收动作,发送端都可在任何时机启动发送动作。但发送端需等待接收端的接收动作发起并开始接收数据之后才可能结束。
2.⾮阻塞通信:把计算和通信重叠起来,从⽽改进并⾏效率
2.1 ⾮重复的⾮阻塞通信(MPI_Isend,MPI_IBsend,MPI_IRsend,MPI_ISsend)
2.2 可重复的⾮阻塞通信(MPI_Send_Init,MPI_Bsend_Init,MPI_Rsend_Init,MPI_Ssend_Init)
2.3 通信结束测试(MPI_Wait,MPI_Test等)
2.4 Probe和Cancel
MPI_Probe和MPI_IProbe可在不实际接收消息的情况下检查消息中包含的信息,然后据此决定接收消息的具体⽅式。
MPI_Cancel⽤于取消等待状态的⾮阻塞操作(发送或接收)。
3.组合发送接收:MPI_Sendrecv
4.点对点通信总结:
各个模式使⽤缓冲的特点可总结为:标准的Send实际利⽤MPI环境提供的默认缓冲区;Bsend实际相当于将MPI环境提供的buffer放在⽤户空间管理;Rsend实际相当于不要缓冲区,但发送端不能提前等待;Ssend实际相当于不要缓冲区,但允许等待。异步⽅式下各个模式⼯作原理类似,只不过将其理解为MPI环境会另起⼀个线程在后台做实际的消息传输,通过MPI_Waitxxx,MPI_Testxxx等机制与MPI进程的主线程进⾏通信和同步。
3.例⼦(send_init.c)
#include "mpi.h"
#include <stdlib.h>
#include <stdio.h>
#define BUFSIZE 5
int main(int argc,char *argv[]){
MPI_Request r;
MPI_Status s;
int flag;
int buf[BUFSIZE];
char pstr[BUFSIZE*(sizeof(int)+8)+50];
int tag=123;
int dest=0;
int rank,size,i,j;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD,&size);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
for(i=0;i<BUFSIZE;i++){
buf[i]=BUFSIZE*rank+1;
}
MPI_Send_init(buf,BUFSIZE,MPI_INT,dest,tag,MPI_COMM_WORLD,&r);
if(rank==0){
int rbuf1[BUFSIZE*size];
MPI_Request *rr=(MPI_Request *)malloc(size*sizeof(MPI_Request));
for(i=0;i<size;i++){
fprintf(stdout,"proc:%d,before Irecv..\n",rank);
MPI_Irecv(rbuf1+i*BUFSIZE,BUFSIZE,MPI_INT,i,tag,MPI_COMM_WORLD,&rr[i]);
fprintf(stdout,"proc:%d,after Irecv..\n",rank);
}
MPI_Start(&r);
MPI_Wait(&r,&s);
MPI_Waitall(size,rr,MPI_STATUSES_IGNORE);
for(i=0;i<size;i++){
sprintf(pstr,"proc:%d received message from %d\n",rank,i);
for(j=0;j<BUFSIZE-1;j++){
sprintf(pstr,"%srbuf1[%d]=%d,",pstr,i*BUFSIZE+j,rbuf1[i*BUFSIZE+j]);
}
sprintf(pstr,"%srbuf1[%d]=%d\n",pstr,i*BUFSIZE+j,rbuf1[i*BUFSIZE+j]);
fprintf(stdout,"%s",pstr);
}
free(rr);进程通信方式
}else{
MPI_Start(&r);
MPI_Wait(&r,&s);
}
MPI_Request_free(&r);
if(rank==0){
MPI_Request sr;
int rbuf2[BUFSIZE];
MPI_Recv_init(rbuf2,BUFSIZE,MPI_INT,MPI_ANY_SOURCE,tag,MPI_COMM_WORLD,&r); fprintf(stdout,"proc: %d,\n",rank);
MPI_Isend(buf,BUFSIZE,MPI_INT,0,tag,MPI_COMM_WORLD,&sr);
fprintf(stdout,"proc: %d,\n",rank);
for(i=0;i<size;i++){
MPI_Start(&r);
MPI_Wait(&r,&s);
sprintf(pstr,"proc: %d received messages from:%d\n",rank,s.MPI_SOURCE); for(j=0;j<BUFSIZE-1;j++){
sprintf(pstr,"%srbuf2[%d]=%d,",pstr,j,rbuf2[j]);
}
sprintf(pstr,"%srbuf2[%d]=%d\n",pstr,j,rbuf2[j]);
fprintf(stdout,"%s",pstr);
}
MPI_Wait(&sr,&s);
MPI_Request_free(&r);
}else{
fprintf(stdout,"proc: d,\n",rank);
MPI_Send(buf,BUFSIZE,MPI_INT,0,tag,MPI_COMM_WORLD);
fprintf(stdout,"proc: %d,\n",rank);
}
MPI_Finalize();
return 0;
}
Linux下编译运⾏指令:
mpicc send_init.c -o send_init
mpirun -np 8 ./send_init
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论