MPI是Message Passing Interface的简称,通过这个协议可以在各个进程——尤其是分布式内存进程——间能够进行通信,交流消息共同完成一个任务。
进行mpi编程的基本流程如下
首先要载入头文件
Fortran 77: include 'mpif.h' Fortran 90: use mpi C/C++: #include "mpi.h"
第二步是初始化MPI环境
Fortran 77/90: Call MPI_INIT(ierror) 其中integer ierror C: int MPI_Init(int *argc, char ***argv); C++: int MPI::Init(int *argc, char ***argv);
第三步是获知参与并行的核的总数
Fortran 77/90: Call MPI_COMM_SIZE(comm, size, ierror) 其中integer comm, size, ierror C: int MPI_Comm_size (MPI_Comm comm, int *size); C++: int MPI::COMM_WORLD.Get_size( );
第四步是得知自己所在的进程的序列号
Fortran 77/90: Call MPI_COMM_RANK(comm, rank, ierror) 其中 integer comm, rank, ierror C: int MPI_Comm_rank(MPI_Comm comm, int *rank); C++: int MPI::COMM_WORLD.Get_rank( );
进行相关计算后
第五步是结束MPI环境
Fortran 77/90: Call MPI_FINALIZE(ierror) 其中integer ierror C: int MPI_Finalize(); C++: MPI::Finalize();
还有两个不常用的方法
计算逝去的时间
Fortran 77/90: double precision MPI_WTIME() C: double MPI_Wtime(); C++: double MPI::Wtime();
和中止MPI环境
Fortran: Call MPI_ABORT(comm, errorcode, ierror) 其中integer comm, errorcode, ierror C: int MPI_Abort(MPI_Comm comm int errorcode ); C++: MPI::COMM_WORLD.Abort( int errorcode );
MPI的数据类型则包括以下几种
C data type |
MPI data type |
char | MPI_CHAR |
short int | MPI_SHORT |
int | MPI_INT |
long int | MPI_LONG |
float | MPI_FLOAT |
double | MPI_DOUBLE |
long double | MPI_LONG_DOUBLE |
Fortran data type |
MPI data type |
INTEGER | MPI_INTEGER |
REAL | MPI_REAL |
REAL*8 | MPI_REAL8 |
DOUBLE PRECISION | MPI_DOUBLE_PRECISION |
COMPLEX | MPI_COMPLEX |
LOGICAL | MPI_LOGICAL |
CHARACTER | MPI_CHARACTER |
通常所用的消息交换方法有以下几种
MPI_SEND&MPI_RECV
Fortran 77/90: Call MPI_SEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, IERROR) 其中<type> BUF(*);INTEGER COUNT, DATATYPE, DEST, TAG, COMM, IERROR C: int MPI_Send(void* buf, int count, MPI_Datatype datatype, int dest,int tag, MPI_Comm comm) C++: MPI::Comm::Send(const void* buf, int count, const MPI::Datatype& datatype, int dest, int tag)
Fortran 77/90: Call MPI_RECV(BUF, COUNT, DATATYPE, SOURCE, TAG, COMM, STATUS, IERROR) 其中<type> BUF(*);INTEGER COUNT, DATATYPE, SOURCE, TAG, COMM, STATUS(MPI_STATUS_SIZE),IERROR C: int MPI_Recv(void* buf, int count, MPI_Datatype datatype, int source,int tag, MPI_Comm comm, MPI_Status *status) C++: MPI::Comm::Recv(void* buf, int count, const MPI::Datatype& datatype,int source, int tag, MPI::Status& status)
这一组方法是阻塞式的,也就是会导致程序等待直到收到对应消息,所以有可能会发生程序死锁例如
if (myid==0) { MPI_RECV(a,100,MPI_INTEGER,0,10,comm, status) MPI_SEND(b,100,MPI_INTEGER,1,11,comm,status) } else { MPI_RECV(a,100,MPI_INTEGER,0,11,comm,status) MPI_SEND(b,100,MPI_INTEGER,0,10,comm,status) }
还有Scatter&Gather
Fortran 77/90: MPI_SCATTER(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR) 其中<type> SENDBUF(*), RECVBUF(*); INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR C: int MPI_Scatter(void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root,MPI_Comm comm) C++: MPI::Comm::Scatter(const void* sendbuf, int sendcount, const MPI::Datatype& sendtype, void* recvbuf, int recvcount, const MPI::Datatype& recvtype, int root)
Fortran 77/90: Call MPI_GATHER(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR) 其中<type> SENDBUF(*), RECVBUF(*);INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR C: int MPI_Gather(void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm) C++: MPI::Comm::Gather(const void* sendbuf, int sendcount, const MPI::Datatype& sendtype, void* recvbuf, int recvcount, const MPI::Datatype& recvtype, int root)
以下是例子
Fortran的
Program mpitest use mpi Implicit None Integer,Parameter :: row=5000 Integer,Parameter :: col=5000 Real(Kind=8) :: mat_a(row,col),mat_b(row,col),mat_c(row,col) Integer :: myid,numprocs,rc,ierr,iprovided Integer(kind=sp) :: startcol,endcol,colsn Integer(kind=sp) :: i,j,k Call MPI_INIT(ierr) Call MPI_COMM_RANK(MPI_COMM_WORLD,myid,ierr) Call MPI_COMM_SIZE(MPI_COMM_WORLD,numprocs,ierr) mat_a=0.0d0 mat_b=0.0d0 mat_c=0.0d0 colsn=col/numprocs startcol=colsn*myid+1 endcol=colsn*(myid+1) If (myid==0) Then mat_a=100.0d0 mat_b=80.0d0 End If Call MPI_SCATTER(mat_a,colsn*row,MPI_DOUBLE_PRECISION,mat_a,colsn*row,MPI_DOUBLE_PRECISION,0,MPI_COMM_WORLD,ierr) Call MPI_SCATTER(mat_b,colsn*row,MPI_DOUBLE_PRECISION,mat_b,colsn*row,MPI_DOUBLE_PRECISION,0,MPI_COMM_WORLD,ierr) mat_c(:,1:colsn)=mat_a(:,1:colsn)-mat_b(:,1:colsn) Call MPI_GATHER(mat_c(:,1:colsn),colsn*row,MPI_DOUBLE_PRECISION,mat_c,colsn*row,MPI_DOUBLE_PRECISION,0,MPI_COMM_WORLD,ierr) Call MPI_FINALIZE(rc) Stop End Program mpitest
C++的
# include <cstdlib> # include <iostream> # include <ctime> # include "mpi.h" using namespace std; int main ( int argc, char *argv[] ); //****************************************************************************80 int main ( int argc, char *argv[] ) { const int row=5000; const int col=5000; int myid; int nprocs; int colsn; int i,j,k; MPI::Init(argc,argv); myid=MPI::COMM_WORLD.Get_rank(); nprocs=MPI::COMM_WORLD.Get_size(); colsn=row/nprocs; double (*mat_a)[col]; double (*mat_b)[col]; double (*mat_c)[col]; double (*tmp_a)[col]; double (*tmp_b)[col]; double (*tmp_c)[col]; tmp_a=new double[colsn][col]; tmp_b=new double[colsn][col]; tmp_c=new double[colsn][col]; if (myid==0) { mat_a=new double[row][col]; mat_b=new double[row][col]; mat_c=new double[row][col]; for ( i = 0; i < row; i++ ) { for ( j = 0; j < col; j++ ) { mat_a[i][j]=100.0; } } for ( i = 0; i < row; i++ ) { for ( j = 0; j < col; j++ ) { mat_b[i][j]=80.0; } } for ( i = 0; i < row; i++ ) { for ( j = 0; j < col; j++ ) { mat_c[i][j]=0.0; } } } else { mat_a=new double[1][col]; mat_b=new double[1][col]; mat_c=new double[1][col]; for ( i = 0; i < colsn; i++ ) { for ( j = 0; j < col; j++ ) { tmp_a[i][j]=0.0; } } for ( i = 0; i < colsn; i++ ) { for ( j = 0; j < col; j++ ) { tmp_b[i][j]=0.0; } } for ( i = 0; i < colsn; i++ ) { for ( j = 0; j < col; j++ ) { tmp_c[i][j]=0.0; } } } MPI::COMM_WORLD.Scatter(mat_a, colsn*col, MPI::DOUBLE, tmp_a, colsn*col,MPI::DOUBLE,0); MPI::COMM_WORLD.Scatter(mat_b, colsn*col, MPI::DOUBLE, tmp_b, colsn*col,MPI::DOUBLE,0); for (i=0;i<colsn;i++) { for (j=0;j<col;j++) { tmp_c[i][j]=tmp_a[i][j]+tmp_b[i][j]; } } MPI::COMM_WORLD.Gather(tmp_c, colsn*col, MPI::DOUBLE, mat_c, colsn*col,MPI::DOUBLE,0); MPI::Finalize(); return 0; }
教程
http://www.lam-mpi.org/tutorials/bindings/
http://www.amazon.com/Introduction-Parallel-Computing-Ananth-Grama/dp/0201648652
http://www.megashare.com/3146342