MPI笔记剖析Word格式文档下载.docx
《MPI笔记剖析Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《MPI笔记剖析Word格式文档下载.docx(25页珍藏版)》请在冰点文库上搜索。
17.MPI通信域
MPI通信域包括两部分:
进程组和通信上下文。
进程组即所有参加通信的进程的集合。
通信上下文提供一个相对独立的通信区域,不同的消息在不同的上下文中进行传递,不同上下文的消息互不干涉,通信上下文可以将不同的通信区别开来。
18.安全的通信调用次序
当两个进程需要相互交换数据时,一个进程的发送操作在前,接收操作在后;
而另一个进程的接收操作在前,发送操作在后,前后两个发送和接收操作要相互匹配。
19.MPI并行程序的两种基本模式
对等模式:
MPI程序的各个进程的功能、地位相同或相近,MPI程序的代码也应该是相近的,所不同的只是处理的对象和操作的数据。
主从模式:
MPI程序的各个进程所起的作用和地位并不相同,一个或者一些进程完成一类任务,而另外的进程完成其它的任务,这些功能或者地位不同的进程所对应的代码也有较大的差别。
20.虚拟进程
虚拟进程(MPI_PROC_NULL)是不存在的假想进程,在MPI中的主要作用是充当真实进程通信的目或源。
一个真实进程向虚拟进MPI_PRC_NULL发送消息时会立即成功返回,一个真实进程从虚拟进程MPI_PROC_NULL的接收消息时也会立即成功返回,并且对接收缓冲区没有任何改变。
21.MPI的四种通信模式
标准通信模式:
是否对发送的数据进行缓存是由MPI自身决定的,而不是由并行程序员来控制。
对于非阻塞通信,发送操作虽然没有完成,但是发送调用可以正确返回。
缓存通信模式:
由用户直接对通信缓冲区进行申请、使用和释放。
缓存通信模式不管接收操作是否启动,发送操作都可以执行,当缓存发送返回后,只有当缓冲区中的消息发送出去后,才可以释放该缓冲区。
对于非阻塞发送,正确退出并不意味者缓冲区可以被其它的操作任意使用。
MPI_BUFFER_ATTACH将大小为size的缓冲区递交给MPI。
MPI_BUFFER_DETACH将提交的大小为size的缓冲区buffer收回,该调用是阻塞调用,它一直等到使用该缓存的消息发送完成后才返回。
#include"
mpi.h"
#include<
stdio.h>
intmain(intargc,char*argv[])
{
intid,size;
MPI_Statusstatus;
MPI_Init(&
argc,&
argv);
MPI_Comm_rank(MPI_COMM_WORLD,&
id);
if(id==0)
{
intse=100;
int*buffer,*dbuffer,bsize,dsize;
MPI_Pack_size(1,MPI_INT,MPI_COMM_WORLD,&
bsize);
buffer=(int*)malloc(bsize+MPI_BSEND_OVERHEAD);
if(!
buffer)
fprintf(stderr,"
Can'
tallocatebsendbufferofsize%d\n"
bsize);
MPI_Abort(MPI_COMM_WORLD,1);
}
MPI_Buffer_attach(buffer,bsize+MPI_BSEND_OVERHEAD);
MPI_Bsend(&
se,1,MPI_INT,1,99,MPI_COMM_WORLD);
MPI_Buffer_detach(&
dbuffer,&
dsize);
else
intre;
MPI_Recv(&
re,1,MPI_INT,0,99,MPI_COMM_WORLD,&
status);
printf("
id=%dreceived%d\n"
id,re);
MPI_Finalize();
}
同步通信模式:
同步发送却必须等到相应的接收进程开始后才可以正确返回。
同步发送返回后,意味着发送缓冲区中的数据已经全部被系统缓冲区缓存,因此发送缓冲区可以被释放或重新使用。
就绪通信模式:
只有当接收进程的接收操作已经启动时,发送进程才可以启动发送操作,发送的正确返回则发送缓冲区可以重复使用。
要求接收操作先于发送操作而被启动。
对于非阻塞发送操作的正确返回,并不意味着发送已完成。
22.非阻塞通信
阻塞通信:
非阻塞通信:
主要用于计算和通信的重叠,在该通信硬件完成该通信操作的同时,处理机可以同时进行计算操作。
由于当非阻塞通信调用返回时一般该通信操作还没有完成,因此对于非阻塞的发送操作,发送缓冲区必须等到发送完成后才能释放。
同理对于非阻塞的接收操作,该调用返回后并不意味着接收消息已全部到达,必须等到消息到达后才可以引用接收到的消息数据。
非阻塞标准通信:
MPI_ISEND:
调用返回立即返回,并不意味着消息已经成功发送它只表示该消息可被发送。
MPI_IRECV:
调用的返回并不意味着已经接收到了相应的消息,它只表示符合要求的消息可以被接收。
非阻塞同步通信:
MPI_ISSEND,返回只是意味着相应的接收操作已经启动,并不表示消息发送的完成。
非阻塞缓存通信:
需要程序员主动为该发送操作提供发送缓冲区。
非阻塞就绪通信:
MPI_IRSEND,当调用启动之前相应的接收操作必须已经启动。
23.非阻塞通信的MPI_WAIT与MPI_TEST
单个非阻塞通信:
MPI_WAIT:
等到非阻塞通信完成后才返回,同时释放该阻塞通信对象。
MPI_TEST:
若该非阻塞通信已经结束,则它和MPI_WAIT的效果完全相同,完成标志flag=true;
若非阻塞通信还没有完成,不必等待该非阻塞通信的完成而是可以直接返回,但是完成标志flag=false,同时也不释放相应的非阻塞通信对象。
多个非阻塞通信:
MPI_WAITANY:
等待非阻塞通信对象表中任何一个非阻塞通信对象i的完成,释放已完成的非阻塞通信对象然后返回,index=i,即完成的是非阻塞通信对象表中的第i个对象对应的非阻塞通信。
MPI_WAITALL:
必须等到非阻塞通信对象表中所有的非阻塞通信对象相应的非阻塞操作都完成后才返回。
MPI_WAITSOME:
只要有一个或多个非阻塞通信完成,则该调用就返回。
MPI_TESTANY:
测试非阻塞通信对象表中是否有任何一个对象已经完成,如真则令flag=ture,否则为false。
MPI_TESTALL:
当所有的非阻塞通信对象都完成时,才使得flag=true返回,并且释放所有的查询对象;
只要有任何一个没有完成,则为false返回。
MPI_TESTSOME:
测试有几个非阻塞通信对象已完成。
24.非阻塞通信对象MPI_Request*
非阻塞通信对象是MPI内部的对象,通过一个句柄存取,可以识别各种通信操作和判断相应的非阻塞操作是否完成。
所有的非阻塞发送或接收通信都会返回一个“非阻塞通信对象“。
非阻塞通信的取消MPI_Cancel:
若取消操作调用时相应的非阻塞通信已经开始,则它会正常完成,不受取消操作的影响;
若取消操作调用时相应的非阻塞通信还没有开始,则可以释放通信占用的资源,取消该非阻塞通信。
对于非阻塞通信,即使调用了取消操作,也必须调用非阻塞通信的完成操作或查询对象的释放操作来释放查询对象。
如果一个非阻塞通信已经被执行了取消操作,则该通信的MPI_WAIT或MPI_TEST将释放取消通信的非阻塞通信对象,并且在返回结果status中指明该通信已经被取消。
判断是否取消MPI_TEST_CANCELLED:
若返回结果flag=true,则表明该通信已经被成功取消,否则说明该通信还没有被取消。
intid,size,flag;
MPI_Requestrequest;
intsbuf=100;
MPI_Send(&
sbuf,1,MPI_INT,1,99,MPI_COMM_WORLD);
intrbuf;
MPI_Irecv(&
rbuf,1,MPI_INT,0,99,MPI_COMM_WORLD,&
request);
MPI_Cancel(&
MPI_Wait(&
request,&
//必须调用此函数,以确保真的取消了
MPI_Test_cancelled(&
status,&
flag);
if(flag)
%d\n"
request);
//若取消成功后,两者一样
MPI_REQUEST_NULL);
}
非阻塞通信对象的释放MPI_Request_free:
直接将该对象所占用的资源释放,原来的非阻塞通信对象request变为MPI_REQUEST_NULL。
如果与该非阻塞通信对象相联系的通信还没有完成,则该对象的资源并不会立即释放,它将等到该非阻塞通信结束后再释放。
25.检查消息是否到达
非阻塞检查MPI_Iprobe:
如果存在一个消息可被接收且该消息的信封和MPI_IPROBE的消息信封相匹配,则该调用返回flag=true和相应的status;
否则,立即返回结果flag=false并且不对status定义。
参数可以是MPI_ANY_SOURCE、MPI_ANY_TAG。
阻塞检查MPI_PROBE:
是一个阻塞调用,只有找到一个匹配的消息到达之后它才会返回。
非阻塞通信有序接收的语义约束:
根据程序的书写顺序,先发送的消息一定被先匹配的接收调用接收。
若在实际运行过程中后发送的消息先到达,它也只能等待。
26.重复非阻塞通信
如果一个通信会被重复执行如循环结构内的通信调用,MPI对这样的通信进行优化。
重复非阻塞通信需要如下步骤:
消息真正开始通信是由MPI_START触发的;
消息的完成操作并不释放相应的非阻塞通信对象只是将其状态置为非活动状态。
初始化重复非阻塞通信
MPI_Send_init:
MPI_Bsend_init:
MPI_Ssend_init:
MPI_Rsend_init:
MPI_Recv_init:
启动非阻塞通信MPI_Start:
MPI_Startall:
一个用MPI_START初始化的发送操作可以被任何接收操作匹配,类似地,一个用MPI_START初始化的接收操作可以接收任何发送操作产生的消息。
27.组通信(通信、同步、计算)
1、广播MPI_Bcast
2、收集MPI_Gather、MPI_Gatherv
3、散发MPI_Scatter、MPI_Scatterv
4、组收集MPI_Allgather、MPI_Allgatherv
5、全交换MPI_Alltoall、MPI_Aalltoallv
stdlib.h>
intmain(intargc,char*argv[])
intrank,size;
intchunk=2;
//每个进程的数据的个数
inti,j;
int*sb;
int*rb;
intstatus,gstatus;
MPI_Comm_rank(MPI_COMM_WORLD,&
rank);
MPI_Comm_size(MPI_COMM_WORLD,&
size);
sb=(int*)malloc(size*chunk*sizeof(int));
rb=(int*)malloc(size*chunk*sizeof(int));
for(i=0;
i<
size;
i++)
for(j=0;
j<
chunk;
j++)
{
sb[i*chunk+j]=i*chunk+j;
printf("
myid=%d,sendtoid=%d,data[%d]=%d\n"
rank,i,j,sb[i*chunk+j]);
rb[i*chunk+j]=0;
MPI_Alltoall(sb,chunk,MPI_INT,rb,chunk,MPI_INT,MPI_COMM_WORLD);
myid=%d,recvfromid=%d,data[%d]=%d\n"
rank,i,j,rb[i*chunk+j]);
free(sb);
free(rb);
6、同步MPI_Barrier
7、归约MPI_Reduce
8、组归约MPI_Allreduce
9、归约并散发MPI_Reduce_scatter
10、扫描MPI_Scan
11、MINLOC和MAXLOC的值对
12、用户自定义归约操作:
MPI_Op_create、MPI_Op_free、MPI_Type_contiguous、MPI_Type_commit、MPI_Op、MPI_Datatype
28.进程组
MPI_Group_size
MPI_Group_rank
MPI_Group_translate_ranks
MPI_Group_compare
MPI_Comm_group
MPI_Group_union
MPI_Group_intersection
MPI_Group_differnce
MPI_Group_incl
MPI_Group_excl
MPI_Group_range_incl
MPI_Group_range_excl
MPI_Group_free
29.通信域
MPI_Comm_size
MPI_Comm_rank
MPI_Comm_compare
MPI_Comm_dup
MPI_Comm_create
MPI_Comm_split
MPI_Comm_free
30.组间通信域
MPI_Comm_test_inter
MPI_Comm_remote_size
MPI_Comm_remote_group
MPI_Intercomm_create
31.属性信息
32.发送不连续的数据:
定义新的数据类型、数据的打包和解包
派生数据类型:
1、连续复制类型的生成MPI_Type_contiguous
2、向量数据类型的生成MPI_Type_vector。
MPI_TYPE_CONTIGUOUS(count,oldtype,newtype)调用等价于MPI_TYPE_VECTOR(count,1,1,oldtype,newtype)或调用MPI_TYPE_VECTOR(1,count,n,oldtype,newtype),n为升序
3、索引数据类型的生成MPI_Type_indexed。
一个MPI_TYPE_VECTOR(count,blocklength,stride,oldtype,newtype)等价于调用MPI_TYPE_INDEXED(count,B,D,oldtype,newtype)
4、结构数据类型的生成MPI_Type_struct。
MPI_TYPE_HINDEXED(count,B,D,oldtype,newtype)等价于调用MPI_TYPE_STRUCT(count,B,D,T,newtype),其中T的每一项都等于oldtype
新类型递交:
MPI_Type_commit
类型释放:
MPI_Type_free
33.地址函数MPI_ADdress
intmain(intargc,char**argv)
intrank;
struct{inta;
doubleb}value;
/*定义一个包含整型和双精度型的结构*/
MPI_Datatypemystruct;
intblocklens[2];
MPI_Aintindices[2];
MPI_Datatypeold_types[2];
MPI_Init(&
argc,&
argv);
MPI_Comm_rank(MPI_COMM_WORLD,&
rank);
blocklens[0]=1;
/*新数据类型中包含一个整型*/
blocklens[1]=1;
/*新数据类型中包含一个双精度型*/
old_types[0]=MPI_INT;
/*新类型的第一个组成部分是整型*/
old_types[1]=MPI_DOUBLE;
/*新类型的第二个组成部分是双精度型*/
/*得到整型和双精度型的相对位置*/
MPI_Address(&
value.a,&
indices[0]);
value.b,&
indices[1]);
/*设置在新类型中的相对偏移*/
indices[1]=indices[1]-indices[0];
indices[0]=0;
MPI_Type_struct(2,blocklens,indices,old_types,&
mystruct);
/*生成新的MPI数据类型*/
MPI_Type_commit(&
/*递交*/
do{
if(rank==0)scanf("
Input:
%d%lf"
&
value.a,&
value.b);
/*只有进程0读需要广播的整型和双精度型数据*/
MPI_Bcast(&
value,1,mystruct,0,MPI_COMM_WORLD);
/*对新数据类型表示的数据进行广播*/
printf("
Process%dgot%dand%lf\n"
rank,value.a,value.b);
}while(value.a>
=0);
MPI_Type_free(&
mystruct);
/*新类型释放*/
MPI_Finalize();
MPI_Type_extent:
以字节为单位返回一个数据类型的跨度extent
MPI_Type_size:
返回给定数据类型有用部分所占空间的大小,即跨度减去类型中的空隙后的空间大小
MPI_Get_elements:
返回的则是以基本的类型为单位的数据的个数
MPI_Get_count:
返回的是以指定的数据类型为单位,接收操作接收到的数据的个数
下界标记类型:
MPI_Type_lb
上界标记类型:
MPI_Type_ub
34.打包与解包
打包(Pack)和解包(Unpack)操作是为了发送不连续的数据,在发送前显式地把数据包装到一个连续的缓冲区;
在接收之后从连续缓冲区中解包。
入口参数position的值是输出缓冲区中用于打包的起始地址,打包后它的值根据打包消息的大小来增加;
出口参数position的值是被打包的消息占用的输出缓冲区后面的第一个地址。
相同类型数据的打包
intid;
intposition,i=100,j=101,a[2];
charbuff[1000];
if(id==0){
position=0;
/*打包的起始位置*/
MPI_Pack(&
i,1,MPI_INT,buff,1000,&
position,MPI_COMM_WORLD);
printf("
position:
position);
/*将整数i打包*/
j,1,MPI_INT,buff,1000,&
/*将整数j打包*/
MPI_Send(buff,position,MPI_PACKED,1