MPI Massage Passing Interface. 一旦完成初始化,在結束MPI之前,除非特別指定,每個進程都會完全一致地執行相同的命令。
在MPI中有上百個調用接口,但是最常用的只有幾個,掌握這幾個調用的用法,就可以快速上手並行計算編程了。一旦入門,之后的學習就會簡單許多。
!!!!!!!!!
MPI_INIT MPI_COMM_RANK MPI_COMM_SIZE MPI_SEND MPI_RECV MPI_FINALIZE
!!!!!!!!!
頭文件
1 use mpi
Fortran90使用 use mpi 加載MPI頭文件。
MPI_INIT,並行環境MPI初始化。
MPI_INIT(ierr)
!!!說明!!!
MPI初始化后,返回一個錯誤代碼 ierr。這個ierr在定義變量的時候,也要定義
說明:MPI程序的第一個調用,完成MPI的初始化工作,所有MPI程序的第一條可執行語句都是這個。一旦完成初始化,在結束MPI之前,除非特別指定,每個進程都會完全一致地執行相同地命令。比如10行,11行,和13行,這些命令所有的進程都會執行一遍,因此,在運行程序后,會看到屏幕上有4行write的內容。但是如果有特別指定,比如17行if判斷,只有符合條件的進程才會執行if內的命令。
MPI_COMM_RANK,當前進程標識。
MPI_COMM_RANK(COMM,RANK,IERROR)
!!!說明!!!
COMM -- 該進程所在的通信域,定義在該通信域中的進程processor都在該通信域中通信。不同的通信域有不同的名稱
RANK -- 調用進程processor在COMM通信域中的標識號,意思就是給不同的進程都取名字,比如用4個核並行計算,那么名字就是0,1,2,3,從0開始標記,並且一般把0,也就是第一個進程看作主進程
IERROR -- 和上邊的ierr一樣,都是返回的錯誤代碼
說明:這一調用返回調用進程在給定的通信域中的進程標識號,有了這一標識號,不同的進程就可以將自身和其它的進程區別開來,實現各進程的並行和協作。
MPI_COMM_SIZE,通信域包含的進程數
MPI_COMM_SIZE(COMM,SIZE,IERROR)
!!!說明!!!
COMM -- 通信域
SIZE -- 該通信域COMM中總共有多少個進程,就是用了多少個核並行計算
IERROR -- 返回的錯誤代碼
說明:這一調用返回給定的通信域中所包括的進程的個數,不同的進程通過這一調用得知在給定的通信域中一共有多少個進程在並行執行。
MPI_SEND,消息發送
MPI_SEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, IERROR)
!!!說明!!!
說明:MPI_SEND將發送緩沖區中的count個datatype數據類型的數據發送到目的進程,目的進程在通信域中的標識號是dest,本次發送的消息標志是tag,使用這一標志,就可以把本次發送的消息和本進程向同一目的進程發送的其它消息區別開來。
MPI_RECV,消息接收
MPI_RECV(BUF, COUNT, DATATYPE, SOURCE, TAG, COMM, STATUS, IERROR)
!!!說明!!!
說明:MPI_RECV從指定的進程source接收消息,並且該消息的數據類型和消息標識和本接收進程指定的datatype和tag相一致,接收到的消息所包含的數據元素的個數最多不能超過count。
MPI_FINALIZE,並行環境MPI結束
MPI_FINALIZE(IERROR)
!!!說明!!!
IERROR -- 返回的錯誤代碼
說明:MPI_FINALIZE是MPI程序的最后一個調用,它結束MPI程序的運行,它是MPI程序的最后一條可執行語句,否則程序的運行結果是不可預知的。
例:Hello_World.f90
1 program main 2 3 use mpi 4 implicit none 5 6 character(len=20) :: message1,message2,message3 7 integer :: myid, ierr, status(mpi_status_size), rc, numprocs 8 9 call MPI_INIT(ierr) 10 call MPI_COMM_RANK( MPI_COMM_WORLD, myid, ierr ) 11 call MPI_COMM_SIZE(MPI_COMM_WORLD,numprocs,ierr) 12 write(*,*) ' process ', myid, ' of ', numprocs, ' is alive' 13 14 if ( myid .eq. 0) then 15 message1 = 'Hello, process 1' 16 call MPI_SEND(message1,20,MPI_CHAR,1,99,MPI_COMM_WORLD,ierr) 17 message2 = 'Hello, process 2' 18 call MPI_SEND(message2,20,MPI_CHAR,2,99,MPI_COMM_WORLD,ierr) 19 message3 = 'Hello, process 3' 20 call MPI_SEND(message3,20,MPI_CHAR,3,99,MPI_COMM_WORLD,ierr) 21 else if ( myid .eq. 1 ) then 22 call MPI_RECV(message1,20,MPI_CHAR,0,99,MPI_COMM_WORLD,status,ierr) 23 write(*,*) message1 24 else if ( myid .eq. 2 ) then 25 call MPI_RECV(message2,20,MPI_CHAR,0,99,MPI_COMM_WORLD,status,ierr) 26 write(*,*) message2 27 else if ( myid .eq. 3 ) then 28 call MPI_RECV(message3,20,MPI_CHAR,0,99,MPI_COMM_WORLD,status,ierr) 29 write(*,*) message3 30 end if 31 32 call MPI_FINALIZE(rc) 33 34 end
編譯:mpif77和mpif90分別編譯並聯接用FORTRAN77和Fortran90編寫的MPI程序,在這里,用mpif90進行編譯。(這里mpifort也可以編譯f90程序)
1 mpif90 Hello_World.f90 -o Hello_World.out ! 或者 mpifort Hello_World.f90 -o Hello_World.out
執行:用mpirun來執行並行計算程序,mpirun –np N program 或者 mpirun –n N program,N 是指定多少個進程同時運行,即多少核並行計算。
1 mpirun -n 4 Hello_World.out ! 或者 mpirun -np 4 Hello_World.out
程序執行結果:
1 process 0 of 4 is alive 2 process 1 of 4 is alive 3 process 2 of 4 is alive 4 Hello, process 2 5 Hello, process 1 6 process 3 of 4 is alive 7 Hello, process 3
可以看到,12行的write命令被執行了4次,但是這4次並不連續,因為21行之后的if判斷搶了先。不同的進程,執行速度不太一樣,有快有慢,就造成了如上的結果。要想讓12行的write命令,4個進程都執行完,才執行之后的命令,要用到MPI_BARRIER同步命令。下一篇博文會介紹。