关于mpi的理论知识以及编写程序来实现数据积分中的梯形积分法。
?幾乎所有人的第一個(gè)程序是從“hello,world”程序開(kāi)始學(xué)習(xí)的
#include "mpi.h" #include <stdio.h> int main(int argc, char* argv[]) {int rank, numproces;int namelen;char processor_name[MPI_MAX_PROCESSOR_NAME];MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD, &rank);//獲得進(jìn)程號(hào)MPI_Comm_size(MPI_COMM_WORLD, &numproces);//返回通信子的進(jìn)程數(shù) MPI_Get_processor_name(processor_name, &namelen);fprintf(stderr, "hello world! process %d of %d on %s\n", rank, numproces, processor_name);MPI_Finalize();return 0; }上述代碼中,第1行中的#include "mpi.h" 頭文件必須包含,在VS2015下編譯生成exe文件(生成在debug文件中),通過(guò)cmd命令,進(jìn)入debug文件夾目錄中,敲入:mpiexec –n 4 TestForMPI.exe。其中命令中-n 4 表示使用4個(gè)進(jìn)程進(jìn)行并行計(jì)算,具體結(jié)果如圖所示:
?
開(kāi)始理論知識(shí)
通過(guò)上述的例子,我們對(duì)MPI編寫(xiě)的并行計(jì)算有了一個(gè)初步的認(rèn)識(shí),但是我們還不知道如何去真正編寫(xiě)一個(gè)MPI的并行程序,這需要我們學(xué)習(xí)一定的理論知識(shí)。在上面的例子中,有幾個(gè)函數(shù)對(duì)于初學(xué)MPI的人來(lái)說(shuō)并不明白是什么意思,下面就從這些函數(shù)入手。
MPI_Init:告知MPI系統(tǒng)進(jìn)行所有必要的初始化設(shè)置。它是寫(xiě)在啟動(dòng)MPI并行計(jì)算的最前面的。具體的語(yǔ)法結(jié)構(gòu)為:
MPI_Init(int* argc_p,char*** argv_p);? 參數(shù)argc_p和argv_p分別指向main函數(shù)中的指針參數(shù),為了弄明白這部分,還得從main函數(shù)的參數(shù)說(shuō)起:C語(yǔ)言規(guī)定main函數(shù)的參數(shù)只能有兩個(gè),習(xí)慣上這兩個(gè)參數(shù)寫(xiě)為argc和argv。因此,main函數(shù)的函數(shù)頭可寫(xiě)為: main (argc,argv)。C語(yǔ)言還規(guī)定argc(第一個(gè)形參)必須是整型變量,argv( 第二個(gè)形參)必須是指向字符串的指針數(shù)組。其中argc參數(shù)表示了命令行中參數(shù)的個(gè)數(shù)(注意:文件名本身也 算一個(gè)參數(shù)),argc的值是在輸入命令行時(shí)由系統(tǒng)按實(shí)際參數(shù)的個(gè)數(shù)自動(dòng)賦予的。例如有命令行為: C:">E6 24 BASIC dbase FORTRAN由于文件名E6 24本身也算一個(gè)參數(shù),所以共有4個(gè)參數(shù),因此argc取得的值為4。argv參數(shù)是字符串指針數(shù)組,其各元素值為命令行中各字符串(參數(shù)均按字符串處 理)的首地址。
然而在MPI_Init函數(shù)中,并不一定都需要設(shè)置argc_p和argv_p這兩個(gè)參數(shù)的,不需要的時(shí)候,將它們?cè)O(shè)置為NULL即可。
通訊子(communicator):MPI_COMM_WORLD表示一組可以互相發(fā)送消息的進(jìn)程集合。
MPI_Comm_rank:用來(lái)獲取正在調(diào)用進(jìn)程的通信子中的進(jìn)程號(hào)的函數(shù)。
MPI_Comm_size:用來(lái)得到通信子的進(jìn)程數(shù)的函數(shù)。
這兩個(gè)函數(shù)的具體結(jié)構(gòu)如下:
int MPIAPI MPI_Comm_rank(__in MPI_Comm comm,__out int* rank);int MPIAPI MPI_Comm_size(__in MPI_Comm comm,__out int* size);它們的第一個(gè)參數(shù)都傳入通信子作為參數(shù),第二參數(shù)都用傳出參數(shù)分別把正在調(diào)用通信子的進(jìn)程號(hào)和通信的個(gè)數(shù)。
MPI_Finalize:告知MPI系統(tǒng)MPI已經(jīng)使用完畢。它總是放到做并行計(jì)算的功能塊的最后面,在此函數(shù)之后就不能再出現(xiàn)任何有關(guān)MPI相關(guān)的東西了。
以上只是表達(dá)了作為一個(gè)MPI并行計(jì)算的基本結(jié)構(gòu),并沒(méi)有真正涉及進(jìn)程之間的通信,為了更好的進(jìn)行并行,必然需要進(jìn)程間的通信,下面介紹兩個(gè)進(jìn)程間通信的函數(shù),它們就是MPI_Send和MPI_Recv,分別用于消息的發(fā)送和接收。
MPI_Send:阻塞型消息發(fā)送。其結(jié)構(gòu)為:
int MPI_Send (void *buf, int count, MPI_Datatype datatype,int dest, int tag,MPI_Comm comm)參數(shù)buf為發(fā)送緩沖區(qū);count為發(fā)送的數(shù)據(jù)個(gè)數(shù);datatype為發(fā)送的數(shù)據(jù)類型;dest為消息的目的地址(進(jìn)程號(hào)),其取值范圍為0到np-1間的整數(shù)(np代表通信器comm中的進(jìn)程數(shù)) 或MPI_PROC_NULL;tag為消息標(biāo)簽,其取值范圍為0到MPI_TAG_UB間的整數(shù);comm為通信器。
MPI_Recv:阻塞型消息接收。
int MPI_Recv (void *buf, int count, MPI_Datatype datatype,int source, int tag, MPI_Comm comm,MPI_Status *status)參數(shù)buf為接收緩沖區(qū);count為數(shù)據(jù)個(gè)數(shù),它是接收數(shù)據(jù)長(zhǎng)度的上限,具體接收到的數(shù)據(jù)長(zhǎng)度可通過(guò)調(diào)用MPI_Get_count函數(shù)得到;datatype為接收的數(shù)據(jù)類型;source為消息源地址(進(jìn)程號(hào)),其取值范圍為0到np-1 間的整數(shù)(np代表通信器comm 中的進(jìn)程數(shù)),或MPI_ANY_SOURCE,或MPI_PROC_NULL;tag為消息標(biāo)簽,其取值范圍為0到MPI_TAG_UB間的整數(shù)或MPI_ANY_TAG;comm為通信器;status返回接收狀態(tài)。
MPI_Status:返回消息傳遞的完成情況。數(shù)據(jù)結(jié)構(gòu)的相關(guān)變量的意義就比較多了,具體可以參數(shù)使用手冊(cè)。
typedef struct { ... ... int MPI_SOURCE; /*消息源地址*/ int MPI_TAG; /*消息標(biāo)簽*/ int MPI_ERROR; /*錯(cuò)誤碼*/ ... ... } MPI_Status;通過(guò)編寫(xiě)程序來(lái)實(shí)現(xiàn)數(shù)據(jù)積分中的梯形積分法。
梯形積分法的基本思想是:將x軸上的區(qū)間劃分為n個(gè)等長(zhǎng)的子區(qū)間。然后計(jì)算子區(qū)間的和。
假設(shè)子區(qū)間的端點(diǎn)為xi和xi+1,那么子區(qū)間的長(zhǎng)度為:h=xi+1-xi。那么梯形的面積就為:
?
由于n個(gè)子區(qū)間是等分的,邊界分別為xi=a和x=b,則:
這片區(qū)域的所有梯形的面積和為:
?
變換為:
因此,串行的程序代碼就可以這樣寫(xiě):
h = (b - a) / h; approx = (f(a) + f(b)) / 2; for (int i = 1; i < n-1; i++) {x_i = a + i*h;approx += f(x_i); } approx = h*approx;通過(guò)對(duì)串行程序的分析,對(duì)于這個(gè)例子,我們可以識(shí)別出兩種任務(wù):第一種獲取單個(gè)矩形區(qū)域的面積,另一種是計(jì)算這些區(qū)域的面積和。
?
假設(shè)求f(x)=x3將梯形劃分為1024個(gè)子區(qū)域計(jì)算[0,3]區(qū)域內(nèi)的積分。 #include "mpi.h" #include <stdio.h> #include <cmath>double Trap(double left_endpt, double right_endpt, double trap_count, double base_len); double f(double x);int main(int argc, char* argv[]) {int my_rank = 0, comm_sz = 0, n = 1024, local_n = 0;double a = 0.0, b = 3.0, h = 0, local_a = 0, local_b = 0;double local_int = 0, total_int = 0;int source;MPI_Init(&argc, &argv);MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);h = (b - a) / n; /* h is the same for all processes */local_n = n / comm_sz; /* So is the number of trapezoids */local_a = a + my_rank*local_n*h;local_b = local_a + local_n*h;local_int = Trap(local_a, local_b, local_n, h);if (my_rank != 0){MPI_Send(&local_int, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);}else{total_int = local_int;for (source = 1; source < comm_sz; source++){MPI_Recv(&local_int, 1, MPI_DOUBLE, source, 0,MPI_COMM_WORLD, MPI_STATUS_IGNORE);total_int += local_int;}}if (my_rank == 0){printf("With n = %d trapezoids, our estimate\n", n);printf("of the integral from %f to %f = %.15e\n", a, b, total_int);}MPI_Finalize();return 0; } //子區(qū)域的積分函數(shù) double Trap(double left_endpt, double right_endpt, double trap_count, double base_len) {double estimate = 0, x = 0;int i;estimate = (f(left_endpt) + f(right_endpt)) / 2.0;for (i = 1; i <= trap_count - 1; i++){x = left_endpt + base_len;estimate += f(x);}estimate = estimate*base_len;return estimate; } //數(shù)學(xué)函數(shù) double f(double x) {return pow(x, 3); }上述代碼中,運(yùn)行結(jié)果:
這段程序代碼中的意思是,通過(guò)輸入的進(jìn)程數(shù),將1024個(gè)劃分的子區(qū)間等分的分配到控制臺(tái)輸入的進(jìn)程(100個(gè))進(jìn)行子任務(wù)求解,求解完成之后,1-99進(jìn)程計(jì)算的結(jié)果值通過(guò)MPI_Send函數(shù)發(fā)送出去,而0號(hào)進(jìn)程使用MPI_Recv函數(shù)接收匯總,將每個(gè)進(jìn)程的結(jié)果求和,得到區(qū)間的積分值。
本次并行計(jì)算消息之間的通信如下圖:
至此,我們已經(jīng)能使用MPI_Send消息發(fā)送函數(shù)和MPI_Recv消息接收函數(shù)進(jìn)行簡(jiǎn)單的并行程序計(jì)算了,但最后的求和都是用號(hào)進(jìn)程去做。
?
轉(zhuǎn)載于:https://www.cnblogs.com/loufangcheng/p/10645093.html
總結(jié)
以上是生活随笔為你收集整理的关于mpi的理论知识以及编写程序来实现数据积分中的梯形积分法。的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: vue axios拦截器的封装
- 下一篇: Hive的日志操作