【MPI学习3】MPI并行程序设计模式:不同通信模式MPI并行程序的设计
學(xué)習(xí)了MPI四種通信模式 及其函數(shù)用法:
(1)標(biāo)準(zhǔn)通信模式:MPI_SEND
(2)緩存通信模式:MPI_BSEND
(3)同步通信模式:MPI_SSEND
(4)就緒通信模式:MPI_RSEND
四種通信模式的區(qū)別都在消息發(fā)送端,而消息接收端的操作都是MPI_RECV。
?
1.標(biāo)準(zhǔn)通信模式
原理圖如下
標(biāo)準(zhǔn)通信模式由MPI決定是否用緩存。
如果MPI決定緩存將要發(fā)出的數(shù)據(jù):發(fā)送操作不管接受操作是否執(zhí)行,都可以進(jìn)行;而且緩存結(jié)束后發(fā)送操作就可以返回,不需要等待接受操作收到數(shù)據(jù)
如果MPI決定不緩存將要發(fā)送的數(shù)據(jù):對于阻塞通信,則要求接受操作執(zhí)行,并且數(shù)據(jù)都發(fā)送到接受緩沖區(qū)了,發(fā)送操作才能夠返回;對于非阻塞通信,發(fā)送操作雖然沒有完成,但是發(fā)送調(diào)用可以正確返回。
?
?
2.緩存通信模式
與標(biāo)準(zhǔn)通信的區(qū)別在于需要自己維護(hù)程序的緩沖區(qū)。
int MPI_Buffer_attach(void *buffer, int size)用于申請緩存
int MPI_Buffer_detach(void **buffer, int *size) 用于釋放緩存 這是一個阻塞調(diào)用 函數(shù)返回表示緩沖區(qū)已經(jīng)被釋放
示例代碼如下:
1 #include "mpi.h" 2 #include <stdio.h> 3 #include <stdlib.h> 4 #define SIZE 6 5 static int src = 0; 6 static int dest = 1; 7 8 void generate_data(double *, int); 9 void normal_recv(double *, int); 10 void buffered_send(double *, int); 11 12 void generate_data(double *buffer, int buff_size){ 13 int i; 14 for (i=0; i<buff_size; i++) buffer[i]=(double)i+1; 15 } 16 17 void normal_recv(double *buffer, int buff_size){ 18 int i,j; 19 MPI_Status status; 20 double *b; 21 22 b = buffer; 23 24 MPI_Recv(b,(buff_size-1),MPI_DOUBLE,src,2000,MPI_COMM_WORLD, &status); 25 fprintf(stderr, "standard receive a message of %d data\n", buff_size-1); 26 for(j=0; j<buff_size-1; j++) fprintf(stderr, "buf[%d]=%f\n",j,b[j]); 27 28 b+=buff_size-1; 29 MPI_Recv(b, 1, MPI_DOUBLE, src, 2000, MPI_COMM_WORLD, &status); 30 fprintf(stderr, "standard receive a message of one data\n"); 31 fprintf(stderr, "buf[0]=%f\n",*b); 32 } 33 34 void buffered_send(double *buffer, int buff_size){ 35 int i,j; 36 void *bbuffer; 37 int size; 38 39 fprintf(stderr, "buffered send message of %d data\n", buff_size-1); 40 for(j=0; j<buff_size-1; j++) fprintf(stderr, "buf[%d]=%f\n",j,buffer[j]); 41 MPI_Bsend(buffer, (buff_size-1), MPI_DOUBLE, dest, 2000, MPI_COMM_WORLD); 42 43 buffer+=buff_size-1; 44 fprintf(stderr, "bufferred send message of one data\n"); 45 fprintf(stderr, "buf[0]=%f\n", *buffer); 46 MPI_Bsend(buffer, 1, MPI_DOUBLE, dest, 2000, MPI_COMM_WORLD); 47 48 MPI_Buffer_detach(&buffer, &size); 49 MPI_Buffer_attach(bbuffer, size); 50 } 51 52 int main(int argc, char *argv[]) 53 { 54 int rank; 55 double buffer[SIZE], *tmpbuffer, *tmpbuf; 56 int tsize, bsize; 57 char *test = NULL; 58 59 MPI_Init(&argc, &argv); 60 MPI_Comm_rank(MPI_COMM_WORLD, &rank); 61 62 if (rank==src) { // 發(fā)送消息進(jìn)程 63 generate_data(buffer, SIZE); 64 MPI_Pack_size(SIZE, MPI_DOUBLE, MPI_COMM_WORLD, &bsize); 65 tmpbuffer = (double*)malloc(bsize+2*MPI_BSEND_OVERHEAD); 66 if (!tmpbuffer) { 67 MPI_Abort(MPI_COMM_WORLD, 1); 68 } 69 // 告訴系統(tǒng)MPI_Bsend用到buffer就去tmpbuffer那里去找 70 MPI_Buffer_attach(tmpbuffer, bsize+2*MPI_BSEND_OVERHEAD); 71 buffered_send(buffer, SIZE); 72 MPI_Buffer_detach(&tmpbuf, &tsize); 73 printf("tsize detach from tmpbuf is : %d\n", tsize); 74 } 75 else if (rank==dest) { 76 normal_recv(buffer, SIZE); 77 } 78 else { 79 MPI_Abort(MPI_COMM_WORLD, 1); 80 } 81 MPI_Finalize(); 82 }代碼輸出結(jié)果是:
總共需要發(fā)送5個double類型,每個類型占8個字節(jié);MPI通信其他附屬信息占200個字節(jié);因此總共緩沖區(qū)的大小的240個字節(jié)。
?
3.同步通信模式
同步發(fā)送進(jìn)程的特點(diǎn)是:發(fā)送操作可以不依賴接受進(jìn)程的相應(yīng)接受操作是否已經(jīng)啟動,但是必須等著接受操作開始執(zhí)行后才能返回;這意味著一旦同步發(fā)送返回后,發(fā)送緩沖區(qū)中的數(shù)據(jù)已經(jīng)全部被系統(tǒng)緩沖區(qū)緩存。“發(fā)送緩沖區(qū)”表示MPI的緩沖區(qū),“系統(tǒng)緩沖區(qū)”指的是操作系統(tǒng)的寫緩沖區(qū),注意二者的區(qū)別。這意味著同步發(fā)送緩沖區(qū)中的數(shù)據(jù)可以被釋放或重新利用。而標(biāo)準(zhǔn)通信模式(或緩存通信模式)中,在用緩存的模式下,發(fā)送操作返回僅僅意味著數(shù)據(jù)都已經(jīng)到發(fā)送緩沖區(qū)中了,數(shù)據(jù)是否到系統(tǒng)緩沖區(qū)不得知。
示例代碼如下:
1 #include "mpi.h" 2 #include <stdio.h> 3 4 #define SIZE 10 5 6 static int src = 0; 7 static int dest = 1; 8 9 int main(int argc, char *argv[]) 10 { 11 int rank; 12 int act_size = 0; 13 int flag, np, rval, i; 14 int buffer[SIZE]; 15 MPI_Status status, status1, status2; 16 int count1, count2; 17 MPI_Init(&argc, &argv); 18 MPI_Comm_rank(MPI_COMM_WORLD, &rank); 19 MPI_Comm_size(MPI_COMM_WORLD, &np); 20 21 if (np!=2) { 22 MPI_Abort(MPI_COMM_WORLD, 1); 23 } 24 act_size = 5; /*最大消息長度*/ 25 if (rank==src) { 26 MPI_Ssend(buffer, act_size, MPI_INT, dest, 1, MPI_COMM_WORLD); 27 fprintf(stderr, "MPI_Ssend %d data,tag=1\n", act_size); 28 act_size = 4; 29 MPI_Ssend(buffer, act_size, MPI_INT, dest, 2, MPI_COMM_WORLD); 30 fprintf(stderr, "MPI_Ssend %d data,tag=2\n", act_size); 31 } 32 else if (rank=dest) { 33 MPI_Recv(buffer, act_size, MPI_INT, src, 1, MPI_COMM_WORLD, &status1); 34 MPI_Recv(buffer, act_size, MPI_INT, src, 2, MPI_COMM_WORLD, &status2); 35 MPI_Get_count(&status1, MPI_INT, &count1); 36 fprintf(stderr, "receive %d data,tag=%d\n",count1, status1.MPI_TAG); 37 MPI_Get_count(&status2, MPI_INT, &count2); 38 fprintf(stderr, "receive %d data,tag=%d\n",count2, status2.MPI_TAG); 39 } 40 MPI_Finalize(); 41 }代碼執(zhí)行結(jié)果如下:
如果將33 34行代碼互換位置,則程序陷入了deadlock:一方面發(fā)送進(jìn)程中tag=1的MPI_Ssend操作一直處于阻塞狀態(tài);另一方面接受進(jìn)程中的tag=2的MPI_Recv操作處于阻塞狀態(tài);兩個進(jìn)程互相等著對方,陷入了死鎖。
?
4. 就緒通信模式
與前幾種通信模式不同,只有當(dāng)接受進(jìn)程的接受操作已經(jīng)啟動時,才可以在發(fā)送端啟動發(fā)送進(jìn)程。
一種可能的就緒通信模式實(shí)現(xiàn)方法如下圖:
?
上圖保證的目標(biāo)是①要先于④執(zhí)行;方法是插入②和③;①一定先于②執(zhí)行,③一定等②成功后才能執(zhí)行,③成功后④才能執(zhí)行。
由此一定保證①先于④執(zhí)行,就保證了就緒通信。
示例代碼如下:
?
1 #include "mpi.h" 2 #include <stdio.h> 3 #include <stdlib.h> 4 5 #define TEST_SIZE 2000 6 7 void test_rsend(); 8 9 int main(int argc, char *argv[]) 10 { 11 MPI_Init(&argc, &argv); 12 test_rsend(); 13 MPI_Finalize(); 14 } 15 16 void test_rsend() 17 { 18 int rank, size; 19 int next, prev; 20 int tag; 21 int count; 22 float send_buf[TEST_SIZE], recv_buf[TEST_SIZE]; 23 MPI_Status status; 24 MPI_Request request; 25 26 MPI_Comm_rank(MPI_COMM_WORLD, &rank); 27 MPI_Comm_size(MPI_COMM_WORLD, &size); 28 29 if (2!=size) { 30 MPI_Abort(MPI_COMM_WORLD, 1); 31 } 32 next = rank + 1; 33 if (next >= size) next = 0; 34 prev = rank - 1; 35 if (prev <0) prev = size-1; 36 37 if (0==rank) { 38 fprintf(stderr, " Rsend Test\n"); 39 } 40 tag = 1456; 41 count = TEST_SIZE/3; 42 if (0==rank) { 43 MPI_Recv(MPI_BOTTOM,0,MPI_INT,next,tag,MPI_COMM_WORLD, &status); 44 fprintf(stderr, " Process %d post Ready send\n", rank); 45 MPI_Rsend(send_buf,count,MPI_FLOAT,next,tag,MPI_COMM_WORLD); 46 } 47 else { 48 fprintf(stderr, " process %d post a receive call\n", rank); 49 MPI_Irecv(recv_buf, TEST_SIZE, MPI_FLOAT,MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD,&request); 50 MPI_Send(MPI_BOTTOM,0,MPI_INT,next,tag,MPI_COMM_WORLD); 51 MPI_Wait(&request, &status); 52 fprintf(stderr, " Process %d Receive Rsend message from %d\n",rank, status.MPI_SOURCE); 53 } 54 }?
代碼執(zhí)行結(jié)果如下:
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/xbf9xbf/p/5204167.html
總結(jié)
以上是生活随笔為你收集整理的【MPI学习3】MPI并行程序设计模式:不同通信模式MPI并行程序的设计的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么用计算机算p a,老师,(P/A,1
- 下一篇: 平台和计算机技术,两大平台技术提升及优势