第五章 消息傳遞接口MPI_第1頁
第五章 消息傳遞接口MPI_第2頁
第五章 消息傳遞接口MPI_第3頁
第五章 消息傳遞接口MPI_第4頁
第五章 消息傳遞接口MPI_第5頁
已閱讀5頁,還剩12頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、第5章 消息傳遞接口MPIMPI(消息傳遞接口)是用于分布式存儲器并行計算機的標準編程環(huán)境。MPI的核心構造是消息傳遞:一個進程將信息打包成消息,并將該消息發(fā)送給其他進程。但是,MPI包含比簡單的消息傳遞更多的內容。MPI包含一些例程,這些例程可以同步進程、求分布在進程集中的數(shù)值的總和、在同一個進程集中分配數(shù)據(jù),以及實現(xiàn)更多的功能。在20世紀90年代早期人們創(chuàng)建了MPI,以提供一種能夠運行在集群、MPP、甚至是共享存儲器機器中的通用消息傳遞環(huán)境。MPI以一種庫的形式發(fā)布,官方的規(guī)范定義了對C和Fortran的綁定(對其他語言的綁定也已經(jīng)被定義)。當今MPI程序員主要使用MPI版本1.1(199

2、5年發(fā)行)。在1997年發(fā)行了一個增強版本的規(guī)范,MPI 2.0,它具有并行I/O、動態(tài)進程管理、單路通信和其他高級功能。遺憾的是,由于它對原有的標準增加了復雜的內容,使得到目前為止,僅有少量的MPI實現(xiàn)支持MPI 2.0。因為這個原因,我們將在本章中集中介紹MPI1.1。5.1 MPI編程的基本概念對MPI的定義是多種多樣的,但不外乎下面三個方面,它們限定了MPI的內涵和外延。1 MPI是一個庫,而不是一門語言。許多人認為MPI就是一種并行語言,這是不準確的。但是按照并行語言的分類,可以把FORTRAN+MPI或C+MPI,看作是一種在原來串行語言基礎之上擴展后得到的并行語言。MPI庫可以被

3、FORTRAN77/C/Fortran90/C+調用,從語法上說,它遵守所有對庫函數(shù)/過程的調用規(guī)則,和一般的函數(shù)/過程沒有什么區(qū)別。2 MPI是一種標準或規(guī)范的代表,而不特指某一個對它的具體實現(xiàn)。迄今為止,所有的并行計算機制造商都提供對MPI的支持,可以在網(wǎng)上免費得到MPI在不同并行計算機上的實現(xiàn),一個正確的MPI程序,可以不加修改地在所有的并行機上運行。3 MPI是一種消息傳遞編程模型,并成為這種編程模型的代表和事實上的標準。MPI雖然很龐大,但是它的最終目的是服務于進程間通信這一目標的。關于什么是MPI的問題設計到多個不同的方面。當我們提到MPI時,不同的上下文中會有不同的含義,它可以是

4、一種編程模型,也可以是一種標準,當然也可以指一類庫。只要全面把握了MPI的概念,這些區(qū)別是不難理解的。的三個主要目的1 較高的通信性能;2 較好的程序可移植性;3 強大的功能。MPI為自己制定了一個雄心勃勃的目標,總結概括起來,它包括幾個在實際使用中都十分重要但有時又是相互矛盾的三個方面,具體地說,包括以下幾個方面:提供應用程序編程接口。 提高通信效率。措施包括避免存儲器到存儲器的多次重復拷貝,允許計算和通信的重疊等。 可在異構環(huán)境下提供實現(xiàn)。提供的接口可以方便 C 語言和 Fortran 77的調用。提供可靠的通信接口。即用戶不必處理通信失敗。定義的接口和現(xiàn)在已有接口(如PVM,NX,Exp

5、ress,p4等)差別不能太大,但是允許擴展以提供更大的靈活性。定義的接口能在基本的通信和系統(tǒng)軟件無重大改變時,在許多并行計算機生產(chǎn)商的平臺上實現(xiàn)。接口的語義是獨立于語言的。 接口設計應是線程安全的。MPI提供了一種與語言和平臺無關,可以被廣泛使用的編寫消息傳遞程序的標準,用它來編寫消息傳遞程序,不僅實用、可移植、高效和靈活,而且和當前已有的實現(xiàn)沒有太大的變化。的語言綁定與實現(xiàn)在MPI-1中,明確提出了MPI和FORTRAN 77與C語言的綁定,并且給出了通用接口和針對FORTRAN 77與C的專用接口說明,MPI-1的成功說明MPI選擇的語言綁定策略是正確和可行的。Fortran90是FOR

6、TRAN的擴充,它在表達數(shù)組運算方面有獨特的優(yōu)勢,還增加了模塊等現(xiàn)代語言的方便開發(fā)與使用的各種特征,它目前面臨的一個問題是Fortran90編譯器遠不如FORTRAN 77編譯器那樣隨處可見,但提供Fortran90編譯器的廠商正在逐步增多。C+作為面向對象的高級語言,隨著編譯器效率和處理器速度的提高,它可以取得接近于C的代碼效率,面向對象的編程思想已經(jīng)被廣為接受,因此在MPI-2中,除了和原來的FORTRAN 77和C語言實現(xiàn)綁定之外,進一步與Fortran90和C+結合起來,提供了四種不同的接口,為編程者提供了更多選擇的余地。但是MPI-2目前還沒有完整的實現(xiàn)版本。下面列出了一些主要的MP

7、I免費實現(xiàn)。表5.1 MPI的一些實現(xiàn)實現(xiàn)名稱研制單位網(wǎng)址MpichArgonne and MSU/mpi/mpichChimpEdinburghftp:/ftp.epcc.ed.ac.uk/pub/packages/chimp/LamOhio State University/lam/MPICH是一種最重要的MPI實現(xiàn),它可以免費從取得。更為重要的是,MPICH是一個與MPI-1規(guī)范同步發(fā)展的版本,每當MPI推出新的版本,就會有相應的MPICH的實現(xiàn)版本,目前MPICH的最新版本是,它支持部分的 MP

8、I-2的特征。Argonne and MSU(阿爾貢)國家試驗室和MSU(密西根州立大學)對MPICH作出了重要的貢獻。在本書中,未特別說明,均指在基于Linux集群的MPICH實現(xiàn)。CHIMP是Edinburgh(愛丁堡、英國蘇格蘭首府)開發(fā)的另一個免費MPI實現(xiàn),是在EPCC(Edinburgh Parallel Computing Centre)的支持下進行的,從可以免費下載該軟件,CHIMP的開發(fā)從1991年到1994年,主要開發(fā)人員有Alasdair Bruce, James (Hamish Mills,和Gordon Smith。LAM (Local Area Multicompu

9、ter也是免費的MPI實現(xiàn),由Ohio State University美國俄亥俄州國立大學 開發(fā),它目前的最新版本是,可以從下載。它主要用于異構的計算機網(wǎng)絡計算系統(tǒng)。編程的基本概念一個MPI并行程序由一組運行在相同或不同計算機/計算結點上的進程或線程構成。這些進程或線程可以運行在不同處理機上,也可以運行在相同的處理機上。為統(tǒng)一起見,MPI 程序中一個獨立參與通信的個體稱為一個進程(process。一個MPI進程通常對應于一個普通進程或線程,但是在共享存儲/消息傳遞混合模式程序中,一個MPI 進程可能代表一組UNIX線程。一個MPI程序中由部分或全部進程構成的一個有序集合稱為一個進程組(pro

10、cess group。進程組中每個進程被賦予一個該組中的序號(rank,用于在該組中標識該進程,稱為進程號。進程號的取值范圍從0開始。MPI程序中進程間的通信、同步等通過通信器(communicator進行(一些資料中將通信器翻譯成通信子,本書中將統(tǒng)一使用術語通信器。MPI的通信器有域內通信器(intra-communicator和域間通信器(inter-communicator兩種,前者用于屬于同一進程組的進程間的通信,后者用于分屬兩個不同進程組的進程間的通信。這里只對域內通信器進行介紹,后文中除非特別提及,“通信器”一詞一律指域內通信器。一個通信器由它所包含的進程組及與之相關聯(lián)的一組屬性(

11、例如進程間的拓撲連接關系 構成。通信器提供進程間通信的基本環(huán)境,MPI 程序中所有通信都必須在特定的通信器中完成。MPI 程序啟動時會自動創(chuàng)建兩個通信器,一個稱為MPI_COMM_WORLD,它包含程序中的所有進程,另一個稱為MPI_COMM_SELF,它是每個進程獨自構成的、僅包含自己的通信器。在MPI 程序中,一個MPI 進程由一個通信器(或進程組 和進程在該通信器(或進程組 中的進程號唯一標識。注意進程號是相對于通信器或進程組而言的:同一個進程在不同的通信器(或進程組中可以有不同的進程號。進程號是在通信器(或進程組 被創(chuàng)建時賦予的。MPI 系統(tǒng)提供了一個特殊進程號MPI_PROC_NUL

12、L,它代表空進程(不存在的進程,與MPI_PROC_NULL進行通信相當于一個空操作,對程序的運行沒有任何影響,它的引入可以方便一些程序的編寫。MPI程序中進程間的通信(communications 通過消息的收發(fā)或同步操作完成。一個消息(message 指在進程間進行的一次數(shù)據(jù)交換。MPI消息包括信封和數(shù)據(jù)兩個部分,信封指出了發(fā)送或接收消息的對象及相關信息,而數(shù)據(jù)是本消息將要傳遞的內容。信封和數(shù)據(jù)又分別包括三個部分??梢杂靡粋€三元組來表示。信封:<源/目,標識,通信域>數(shù)據(jù):<起始地址,數(shù)據(jù)個數(shù),數(shù)據(jù)類型>以MPI_SEND和MPI_RECV (receive為例,下

13、圖分別給出了它們的信封和數(shù)據(jù)部分。圖5.1 MPI_SEND語句的消息信封和消息數(shù)據(jù)圖5.2 MPI_RECV語句的消息信封和消息數(shù)據(jù)在消息信封中除了源/目外,為什么還有tag標識呢?這是因為,當發(fā)送者發(fā)送兩個相同類型的數(shù)據(jù)給同一個接收者時,如果沒有消息標識,接收者將無法區(qū)別這兩個消息。一個接收操作對消息的選擇是由消息的信封管理的。如果消息的信封與接收操作所指定的值source,tag和comm相匹配,那么這個接收操作能接收這個消息。接收者可以給source指定一個任意值MPI_ANY_SOURCE,標識任何進程發(fā)送的消息都可以接收,即本接收操作可以匹配任何進程發(fā)送的消息,但其它的要求還必須滿

14、足,比如tag的匹配;如果給tag一個任意值MPI_ANY_TAG,則任何tag都是可接收的。在某種程度上,類似于統(tǒng)配符的概念。MPI_ANY_SOURCE和MPI_ANY_TAG可以同時使用或分別單獨使用。但是不能給comm指定任意值。如果一個消息被發(fā)送到接收進程,接收進程有匹配的通信域,有匹配的 source (或其source = MPI_ANY_SOURCE,有匹配的tag(或其tag = MPI_ANY_TAG,那么這個消息能被這個接收操作接收。5.2 MPI的原始數(shù)據(jù)類型MPI系統(tǒng)中數(shù)據(jù)的發(fā)送與接收操作都必須指定數(shù)據(jù)類型。數(shù)據(jù)類型可以是MPI系統(tǒng)預定義的,稱為原始數(shù)據(jù)類型,也可以是

15、用戶在原始數(shù)據(jù)類型的基礎上自己定義的數(shù)據(jù)類型。在此只介紹原始數(shù)據(jù)類型,自定義數(shù)據(jù)類型請參看參考文獻2。MPI為C預定義的原始數(shù)據(jù)類型在表1中給出。除表中列出的外,某些MPI系統(tǒng)可能支持更多的原始數(shù)據(jù)類型,如MPI_INTEGER2,MPI_LONG_LONG_INT,等等。表5.2 MPI原始數(shù)據(jù)類型MPI數(shù)據(jù)類型C類型MPI_INTMPI_FLOATMPI_DOUBLEMPI_SHORTMPI_LONGMPI_CHAR MPI_UNSIGNED_CHARMPI_UNSIGNED_SHORTMPI_UNSIGNEDMPI_UNSIGNED_LONGMPI_LONG_DOUBLEMPI_BYTE

16、MPI_PACKEDintfloatdoubleshortlongcharunsigned charunsigned shortunsignedunsigned longlong doubleunsigned char無MPI系統(tǒng)的原始數(shù)據(jù)類型只適合于收發(fā)一組在內存中連續(xù)存放的數(shù)據(jù)。當要收發(fā)的數(shù)據(jù)在內存中不連續(xù),或由不同數(shù)據(jù)類型構成時,則需要將數(shù)據(jù)打包或者使用自定義的數(shù)據(jù)類型。自定義數(shù)據(jù)類型用于描述要發(fā)送或接收的數(shù)據(jù)在內存中的確切分布。數(shù)據(jù)類型是MPI的一個重要特征,它的使用可有效地減少消息傳遞的次數(shù),增大通信粒度,并且,與數(shù)據(jù)打包相比,在收/發(fā)消息時可以避免或減少數(shù)據(jù)在內存中的拷貝、復制。關

17、于MPI自定義數(shù)據(jù)類型的詳細使用,限于篇幅,在此不作詳細說明,有興趣的讀者請參看參考文獻文獻2。5.3 MPI程序的基本結構一個MPI程序的各個進程通過調用MPI函數(shù)進行通信,協(xié)同完成一項計算任務。在MPI的C語言接口中,所有函數(shù)名均采用MPI_Xxxxx的形式,如MPI_Send,MPI_Type_commit等等,它們以MPI_開始,以便與其他函數(shù)名相區(qū)別,前綴MPI_之后的第一個字母大寫,其余字母一律小寫。MPI的C語言接口函數(shù)通常返回一個整數(shù)值表示操作成功與否,返回值為MPI_SUCCESS (0 表示操作成功,否則表示操作的錯誤碼。MPI接口中除了函數(shù)和SUBROUTINE外,還定義

18、了一組常量及C變量類型,它們的命名規(guī)則為:所有常量的名稱全部大寫,如MPI_COMM_WORLD,MPI_INT等;而C變量類型的命名則與C函數(shù)一樣,如MPI_Datatype,MPI_Status等。MPI 并行程序和串行程序沒有很大的差別,它們通過對MPI函數(shù)的調用來實現(xiàn)特定的并行算法。一個MPI 并行程序主要由三個部分組成:1 進入并行環(huán)境:調用MPI_Init來啟動并行計算環(huán)境,它包括在指定的計算結點上啟動構成并行程序的所有進程以及構建初始的MPI 通信環(huán)境和通信器MPI_COMM_WORLD、MPI_COMM_SELF。2 主體并行任務:這是并行程序的實質部分,所有需要并行來完成的任

19、務都在這里進行。在這個部分中,實現(xiàn)并行算法在并行計算機上的執(zhí)行過程。3 退出并行環(huán)境:調用MPI_Finalize退出并行環(huán)境。一般說來,退出并行計算環(huán)境后程序的運行亦馬上結束。下面是C語言MPI程序的典型結構#include "mpi.h". .int main(int argc, char *argvint myrank, nprocs;. .MPI_Init(&argc, &argv;MPI_Comm_size(MPI_COMM_WORLD, &nprocs;MPI_Comm_rank(MPI_COMM_WORLD, &myrank;.

20、 .MPI_Finalize(;. .用C語言編寫的MPI 程序中每個源文件必須包含MPI的C語言頭文件mpi.h,以便得到MPI函數(shù)的原型說明及MPI預定義的常量和類型。注意源文件中包含頭文件“mpi.h” 時不要含路徑,必要時可在編譯時通過“-I” 選項指定mpi.h所在的路徑,以方便程序在不同MPI 系統(tǒng)間的移植。MPI_Init函數(shù)用于初始化MPI系統(tǒng)。在調用其他MPI函數(shù)前(除MPI_Initialized外 必須先調用該函數(shù)。在許多MPI系統(tǒng)中,第一個進程通過MPI_Init來啟動其他進程。注意要將命令行參數(shù)的地址(指針 &argc和&argv傳遞給MPI_Init

21、,因為MPI程序啟動時一些初始參數(shù)是通過命令行傳遞給進程的,這些參數(shù)被添加在命令行參數(shù)表中,MPI_Init通過它們得到MPI程序運行的相關信息,如需要啟動的進程數(shù)、使用那些結點、以及進程間的通信端口等,返回時會將這些附加參數(shù)從參數(shù)表中去掉。因此一個MPI程序如果需要處理命令行參數(shù),最好在調用MPI_Init之后再進行處理,這樣可以避免遇到MPI系統(tǒng)附加的額外參數(shù)。函數(shù)MPI_Comm_size與MPI_Comm_rank分別返回指定通信器(這里是MPI_COMM_WORLD,它包含了所有進程 中進程的數(shù)目以及本進程的進程號。MPI_Finalize函數(shù)用于退出MPI系統(tǒng)。調用MPI_Fina

22、lize之后不能再調用任何其他MPI 函數(shù)。各MPI函數(shù)的詳細使用方法請參看下一節(jié)的例子程序及附錄3,在此先不作詳細說明。5.4 MPI通信簡介點到點通信和通信模式MPI最基本的通信模式是在一對進程之間進行的消息收發(fā)操作:一個進程發(fā)送消息,另一個進程接收消息。這種通信方式稱為點對點通信(point to point communications。MPI提供兩大類型的點對點通信函數(shù)。第一種類型稱為阻塞型(blocking,第二種類型稱為非阻塞型(non blocking。阻塞型函數(shù)需要等待指定操作的實際完成,或至少所涉及的數(shù)據(jù)已被MPI系統(tǒng)安全地備份后才返回。如MPI_Send 和MPI_Rec

23、v都是阻塞型的。MPI_Send 函數(shù)返回時表明數(shù)據(jù)已經(jīng)發(fā)出或已被MPI系統(tǒng)復制,隨后對發(fā)送緩沖區(qū)的修改不會影響所發(fā)送的數(shù)據(jù)。而MPI_Recv返回時,則表明數(shù)據(jù)已經(jīng)接收到并且可以立即使用。阻塞型函數(shù)的操作是非局部的,它的完成可能需要與其他進程進行通信。非阻塞型函數(shù)調用總是立即返回,而實際操作則由MPI系統(tǒng)在后臺進行。非阻塞型函數(shù)名MPI_前綴之后的第一個字母為“I”,最常用的非阻塞型點對點通信函數(shù)包括MPI_Isend 和MPI_Irecv。在調用了一個非阻塞型通信函數(shù)后,用戶必須隨后調用其他函數(shù),如MPI_Wait 或MPI_Test等,來等待操作完成或查詢操作的完成情況。在操作完成之前對

24、相關數(shù)據(jù)區(qū)的操作是不安全的,因為隨時可能與正在后臺進行的通信發(fā)生沖突。非阻塞型函數(shù)調用是局部的,因為它的返回不需要與其他進程進行通信。在有些并行系統(tǒng)上,通過非阻塞型函數(shù)的使用可以實現(xiàn)計算與通信的重疊進行。此外,對于點對點消息發(fā)送,MPI 提供四種發(fā)送模式,這四種發(fā)送模式的相應函數(shù)具有一樣的調用參數(shù),但它們發(fā)送消息的方式或對接收方的狀態(tài)要求不同。標準模式(standard mode 由MPI系統(tǒng)來決定是先將消息拷貝至一個緩沖區(qū)然后立即返回(此時消息的發(fā)送由MPI系統(tǒng)在后臺進行,還是等待將數(shù)據(jù)發(fā)送出去后再返回。大部分MPI系統(tǒng)預留了一定大小的緩沖區(qū),當發(fā)送的消息長度小于緩沖區(qū)大小時會將消息拷貝到緩

25、沖區(qū)然后立即返回,否則則當部分或全部消息發(fā)送完成后才返回。標準模式發(fā)送操作是非局部的,因為它的完成需要與接收方聯(lián)絡。標準模式阻塞型發(fā)送函數(shù)是MPI_Send。緩沖模式(buffered mode MPI系統(tǒng)將消息拷貝至一個用戶提供的緩沖區(qū)然后立即返回,消息的發(fā)送由MPI系統(tǒng)在后臺進行。用戶必須確保所提供的緩沖區(qū)足以容下采用緩沖模式發(fā)送的消息。當消息大小超過緩沖區(qū)容量時,應用程序會收到錯誤匯報。緩沖模式發(fā)送操作是局部的,因為函數(shù)不需要與接收方聯(lián)絡即可立即完成(返回。緩沖模式阻塞型發(fā)送函數(shù)為MPI_Bsend。同步模式(synchronous mode 在標準模式的基礎上要求確認接收方已經(jīng)開始接收

26、數(shù)據(jù)后函數(shù)調用才返回。即發(fā)送動作的結束不僅意味著發(fā)送緩沖區(qū)已經(jīng)可以用于其它用途,而且還表示接收端也執(zhí)行了一定程序的接收工作。顯然,同步模式的發(fā)送是非局部的。同步模式阻塞型發(fā)送函數(shù)為MPI_Ssend。就緒模式(ready mode 調用就緒模式發(fā)送時必須確保接收方已經(jīng)處于就緒狀態(tài)(正在等待接收該消息,否則將產(chǎn)生一個錯誤。該模式設立的目的是在一些以同步方式工作的并行系統(tǒng)上由于發(fā)送時可以假設接收方已經(jīng)準備好接收而減少一些握手開銷。如果一個使用就緒模式的MPI 程序是正確的,則將其中所有就緒模式的消息發(fā)送改為標準模式后也應該是正確的。就緒模式阻塞型發(fā)送函數(shù)為MPI_Rsend。表5.3 MPI點對點

27、通信類型及模式匯總函數(shù)類型通信模式阻塞型非阻塞型消息發(fā)送函數(shù)標準模式MPI_SendMPI_Isend緩沖模式MPI_BsendMPI_Ibsend同步模式MPI_SsendMPI_Issend就緒模式MPI_RsendMPI_Irsend消息接收函數(shù)MPI_RecvMPI_Irecv消息檢測函數(shù)MPI_ProbeMPI_Iprobe等待通信完成或查詢完成情況MPI_WaitMPI_TestMPI_WaitallMPI_TestallMPI_WaitanyMPI_TestanyMPI_WaitsomeMPI_Testsome釋放通信請求MPI_Request_free取消通信MPI_Cance

28、lMPI_Test_cancelled具體函數(shù)的使用請參看附錄3。各通信模式的詳細分析和舉例限于篇幅在此不作詳細說明,有興趣的讀者請參看參考文獻2。聚合通信指在一個通信器的所有進程間同時進行的通信。聚合通信總是在一個通信器中的所有進程間進行,調用一個聚合通信函數(shù)時,通信器中的所有進程必須同時調用同一函數(shù),共同參與操作。聚合通信包括障礙同步(MPI_Barrier、廣播(MPI_Bcast、數(shù)據(jù)收集(MPI_Gather、數(shù)據(jù)散發(fā)(MPI_Scatter、數(shù)據(jù)轉置(MPI_Alltoall和歸約(MPI_Reduce。1. 障礙同步障礙同步函數(shù)MPI_Barrier用于一個通信器中所有進程的同步

29、。調用該函數(shù)時進程將處于等待狀態(tài),直到通信器中所有進程都調用了該函數(shù)后才繼續(xù)執(zhí)行。2. 廣播指一個進程(稱為根進程 同時發(fā)送同樣的消息給通信器中的所有其他進程。MPI 的廣播函數(shù)是MPI_Bcast。3. 數(shù)據(jù)收集數(shù)據(jù)收集操作指一個進程,稱為根進程,從指定通信器中的所有進程,包括根進程自己,收集數(shù)據(jù)。MPI的基本數(shù)據(jù)收集函數(shù)為MPI_Gather,它從每個進程收集相同長度的數(shù)據(jù)。如果從各個進程收集的數(shù)據(jù)長度不同,則應該調用函數(shù)MPI_Gatherv。函數(shù)MPI_Allgather用于在通信器中的所有進程中同時進行數(shù)據(jù)收集,它的作用相當于先用MPI_Gather將數(shù)據(jù)收集到一個進程中,緊接著用M

30、PI_Bcast將收集到的數(shù)據(jù)廣播給其他進程。類似地,MPI_Allgatherv用于收集不同長度的數(shù)據(jù)到通信器中的所有進程中。4. 數(shù)據(jù)散發(fā)數(shù)據(jù)散發(fā)函數(shù)MPI_Scatter正好是數(shù)據(jù)收集函數(shù)MPI_Gather的逆向操作,它將一個進程中的數(shù)據(jù)按塊散發(fā)給通信器中的所有進程,散發(fā)給每個進程的數(shù)據(jù)塊長度相同。函數(shù)MPI_Scatterv用于散發(fā)不同長度的數(shù)據(jù)塊。5. 數(shù)據(jù)轉置函數(shù)MPI_Alltoall用于同時進行收集和散發(fā)操作:通信器中所有進程從其他進程收集數(shù)據(jù),同時將自己的數(shù)據(jù)散發(fā)給其他進程。它的作用相當于將一個分布式存儲的數(shù)據(jù)場在處理機間進行一次轉置。函數(shù)MPI_Alltoall要求參與操

31、作的所有數(shù)據(jù)塊長度一樣,如果數(shù)據(jù)塊長度不同,則應該調用MPI_Alltoallv函數(shù)。6. 歸約歸約運算是指在分布在不同進程的數(shù)據(jù)間進行指定的運算,常用的運算有求和、求最大或最小值等。MPI 的歸約函數(shù)中可以使用預定義的運算(如MPI_SUM,MPI_MAX 等,參看附錄3,也可以使用用戶自行定義的運算(參看MPI_Op_create。MPI 用于歸約操作的基本函數(shù)是MPI_Reduce,它在指定的進程(稱為根進程 中返回歸約運算結果。如果希望所有進程都得到歸約運算的結果,則可使用函數(shù)MPI_Allreduce。此外,MPI 還提供一個函數(shù)MPI_Scan,稱為前綴歸約或掃描歸約,用于計算數(shù)據(jù)

32、的部分和。表5.4 MPI 點對點通信類型及模式匯總類型函數(shù)名含義同步MPI_Barrier路障同步廣播MPI_Bcast一對多廣播同樣的消息數(shù)據(jù)收集MPI_Gather多對一收集各個進程的消息MPI_GathervMPI_Gather的一般化MPI_Allgather全局收集MPI_AllgathervMPI_Allgather的一般化數(shù)據(jù)散發(fā)MPI_Scatter一對多散播不同的消息MPI_SvcatterMPI_Scatter的一般化數(shù)據(jù)轉置MPI_Alltoall多對多全局交換消息MPI_AlltoallvMPI_Alltoallv的一般化歸約MPI_Reduce多對一歸約MPI_Al

33、lreduce全歸約MPI_Reduce_scatter歸約并散播MPI_Scan掃描具體函數(shù)的使用請參看附錄3。5.5 一個經(jīng)典的MPI程序實例數(shù)值積分(值計算代碼5.1 是取自MPICH 的一個程序實例,它展示了C語言MPI并行程序的結構。該程序用下面的公式計算定積分的近似值: 式5.1其中n>0為積分區(qū)間數(shù)。為積分步長。 為積分區(qū)間的中點。被積函數(shù)。 假設總進程數(shù)為p (程序中的numprocs 變量,各進程分別負責計算式5.1中的一部分計算區(qū)間,然后再調用MPI_Reduce將各進程的結果加起來。代碼中計算區(qū)間采用循環(huán)分配的方式,即將計算公式寫成:每個進程獨立計算上式中的一個內層

34、求和,然后再將這些結果加起來,如圖5.1。圖5.3 值計算分10小塊時圖示(10小塊的面積相加近似于曲線f(x發(fā)在0-1區(qū)間所圍的面積)代碼5.1 MPI程序實例:數(shù)值積分(值計算。文件名: code/mpi/cpi.c1 /* 程序來源:MPICH examples/cpi.c */2 #include "mpi.h"3 #include 45 double f( double a return (4.0 / (1.0 + a*a; /*定義被積函數(shù)f(x67 int main( int argc, char *argv /* argc 和argv 分別是命令行參數(shù)的個數(shù)

35、和參數(shù)數(shù)組的指針8 9 int n, myid, numprocs, i, namelen; /*n :計算區(qū)間分區(qū)(條)數(shù);myid:本進程的進程號; numprocs :進程組中進程數(shù);i:進程中計算各個小區(qū)間的循環(huán)控制變量;namelen:處理器名長度;11 double mypi, pi, h, sum, x; /*mypi :各進程中所有小區(qū)間面積的求和值;pi:最終的計算值; h:小區(qū)間寬度; sum:進程中所有小區(qū)間高的和; x:每個小區(qū)間中點的x值;12 double startwtime, endwtime;13 char processor_nameMPI_MAX_PROC

36、ESSOR_NAME; /*processor_name:處理器名存儲單元1415 MPI_Init(&argc,&argv;16 MPI_Comm_size(MPI_COMM_WORLD,&numprocs;17 MPI_Comm_rank(MPI_COMM_WORLD,&myid;18 MPI_Get_processor_name(processor_name,&namelen; 19 fprintf(stderr,"Process%don %sn", myid, processor_name;20 if (myid = 0 21

37、 n=10000;22 startwtime = MPI_Wtime(;23 24 MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD; /*0:root根進稱號25 h = 1.0 / (double n;26 sum = 0.0;27 for (i = myid; i < n; i += numprocs 28 x = h * (doublei + 0.5;29 sum += f(x;30 31 mypi = h * sum;32 MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM,

38、0, MPI_COMM_WORLD;33 if (myid = 0 34 endwtime = MPI_Wtime(;35 printf("pi is approximately %.16f, error is %.16fn", pi, pi - PI25DT;36 printf("wall clock time = %fn", endwtime-startwtime;37 38 MPI_Finalize(;3940 return 0;41 程序詳解:第2行:#include "mpi.h"是預處理指令,用于包含mpi的頭文件。第5行

39、:double f(double a return (4.0/(1.0+a*a;定義被積函數(shù)f(x。第7行:int main( int argc, char *argv是主函數(shù),包含了argc和argv參數(shù),它們將被傳入用于初始化MPI的函數(shù)。第10行:定義一個比較精確的25位值作為標準值,以分析本程序計算結果的誤差。第12行:double startwtime, endwtime定義變量開始時間startwtime和結束時間endwtime。均為MPI_Wtime(的返回值。第15行:MPI_Init(&argc,&argv被每一個MPI進程調用的MPI函數(shù)都是MPI_Ini

40、t。該函數(shù)指示系統(tǒng)完成所有初始化工作,以備對后續(xù)MPI庫的調用進行處理,因此,MPI_Init要在調用任何MPI函數(shù)之前調用。argc 和argv 分別是命令行參數(shù)的個數(shù)和參數(shù)數(shù)組的指針(通過C的main 函數(shù)得到,必須將它們如實傳遞給MPI 系統(tǒng)。MPI 系統(tǒng)通過它們得到所需的參數(shù),并且會將MPI 系統(tǒng)專用的參數(shù)刪除而僅留下供用戶程序使用的參數(shù)。第16行:MPI_Comm_size(MPI_COMM_WORLD,&numprocs當MPI初始化后,每一個活動進程變成一個叫做MPI_COMM_WORLD的默認通信域中的成員。一個通信域是不透明的對象,提供了在進程之間傳遞消息的環(huán)境。MP

41、I_Comm_size(MPI_COMM_WORLD,&numprocs用numprocs返回通信域MPI_COMM_WORLD中的進程數(shù)。第17行:MPI_Comm_rank(MPI_COMM_WORLD,&myid用myid返回通信域MPI_COMM_WORLD中本進程的進程號。第18行:MPI_Get_processor_name(processor_name,&namelen 該函數(shù)返回運行本進程的處理器名稱。參數(shù)processor_name應該提供不少于MPI_MAX_PROCESSOR_NAME 個字節(jié)的存儲空間用于存放處理器名稱。第20-23行:是僅進程0

42、執(zhí)行的代碼,給n賦值10000意味著將0-1的積分區(qū)間分成10000小塊,對每一個小塊計算面積。同時,獲取計算機開始的時間。第24行:MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD是廣播函數(shù)。MPI_Bcast(void *buffer, int count,MPI_Datatype datatype, int root,MPI_Comm comm表示通信器comm 中進程號為root 的進程(稱為根進程 將自己buffer 中的內容發(fā)送給通信器中所有其他進程。參數(shù)buffer、count 和datatype 的含義與點對點通信函數(shù)(如MPI_S

43、end 和MPI_Recv 相同。則MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD表示通信器MPI_COMM_WORLD中進程號為0的進程將自己n 中的內容發(fā)送給通信器中所有其他進程。第25-26行:為即將開始的計算做準備。第27-30行:計算本進程所分配的各小塊的高度和。每一進程均從i= myid開始,每做一次計算往后跳numprocs塊。這樣,每個進程均計算總小塊數(shù)10000的一1/numprocs。第31行:mypi = h * sum將每個進程所得的各小塊的高度和與小塊寬度相乘即得本進程所得的小塊面積和即PI的部分值。第32行:MPI_R

44、educe(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD將各進程所得的PI的部分值進行歸約。&mypi為各個進程的歸約元素的地址,&pi為歸約計算(MPI_SUM)之后結果的存放地址,為執(zhí)行歸約的次數(shù),MPI_DOUBLE為元素類型,MPI_SUM為歸約操作符(其它的操作符請參看附錄),0為得到結果的進程號,MPI_COMM_WORLD為通信域。第33-37行: 0號進程執(zhí)行的代碼,進程首先獲取時間,再用現(xiàn)在的時候減去初始獲取的時間即得到程序執(zhí)行的時間并顯示。第38行:MPI_Finalize(在一個

45、進程執(zhí)行完其全部MPI庫函數(shù)調用后,將調用函數(shù)MPI_Finalize,從而讓系統(tǒng)釋放分配給MPI的資源(例如內存等)。所有進程均從前到后地執(zhí)行本程序,各進程均為變量分配內存。部分只有特定進程才執(zhí)行的代碼均放在條件語句中,一般用myid作為條件來決定本進程是否執(zhí)行,如第20-23行。每個進程都可有輸出到屏幕操作,但其它進程的輸出內容只會顯示在根進程所在節(jié)點的屏幕上。運行結果:1 mpinode2 examples$ su2 Password3 mpinode2 examples# ./bin/mpicc o mycpi ./cpi.c4 mpinode2 examples# scp /usr/

46、local/mpich/examples/mycpi node1: /usr/local/mpich/examples/5 mpinode2 examples# scp /usr/local/mpich/examples/mycpi node3: /usr/local/mpich/examples/6 mpinode2 examples# scp /usr/local/mpich/examples/mycpi node4: /usr/local/mpich/examples/7 mpinode2 examples#exit8 exit9 mpinode2 examples$ ./bin/mpi

47、run -np 4 mycpi10 Process 0 on node211 Process 1 on node112 Process 2 on node313 Process 3 on node415 wall clock time = 0.048537說明:本MPICH安裝在路徑/usr/local下,文件cpi.c默認在/usr/local/mpich/examples下。例子中為用4個節(jié)點運算的結果。要編譯程序,首先進入root用戶,如第1-2行所示。第3行編譯cpi.c文件,用mpich提供的mpicc編譯時要加上路徑,否則系統(tǒng)默認mpicc為LAM實現(xiàn),導致編譯失敗,參數(shù)“-o”后

48、為編譯后的文件名。第4-7行將編譯所得的mycpi文件分別復制到節(jié)點1、節(jié)點3、節(jié)點4的同樣的目錄下,因為操作在節(jié)點2上進行,節(jié)點2已有mycpi文件。第7-8行退出root用戶,因為配置并行環(huán)境時各節(jié)點只給其它節(jié)點的mpi用戶放權,因此進行運算時需在用戶mpi下進行。第9行用mpirun運行mpi程序編譯后所得的文件mycpi,-np后為節(jié)點數(shù)目。第10-15行為此并行程序的輸出結果。5.6 MPI編程模式MPI 并行程序從程序結構上可以分成三種編程模式,包括主從模式(Masterslave、單程序多數(shù)據(jù)模式(SPMD,即Single Program Multiple Data 和多程序多數(shù)

49、據(jù)模式(MPMD,即Multiple Programs Multiple Data。這些編程模式既可以從源代碼的組織形式來劃分,也可以從實際程序所執(zhí)行的代碼來劃分。它們之間有時并沒有非常明確的界線。如果從源代碼的組織形式來劃分,SPMD模式的MPI程序中只有一套源代碼,所有進程運行的都是該代碼;master/slave 模式的MPI程序包含兩套源代碼,主進程運行其中一套代碼,而從進程運行另一套代碼;MPMD模式則包含多套源代碼,不同進程分別執(zhí)行其中的一套代碼。如果從實際程序所執(zhí)行的代碼來劃分,一個并行程序屬于哪種編程模式,取決于程序中各進程實際執(zhí)行的代碼是否相同,以及是否具有client/server的特征。如果各進程執(zhí)行的代碼大體是一樣的則可以看作SPMD模式,如果具有client/server特征則被認為是master/slave模式,否則則為MPMD模式。在這種編程模式劃分中,master/slave和MPMD模式也可以只用一套源碼,不同進程執(zhí)行的代碼通過在程序中對進程號的條件判斷來實現(xiàn)。實際編程時,相對于使用多套不同的源碼而言,使用一套源碼更便于代碼的維護,并且MPI并行程序

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論