MPI的两种最基本的并行程序设计模式 即对等模式和主从模式。
对等模式:各个部分地位相同,功能和代码基本一致,只不过是处理的数据或对象不同,也容易用同样的程序来实现。
主从模式:分为主进程和从进程,程序通信进程之间的一种主从或依赖关系 。MPI程序包括两套代码,主进程运行其中一套代码,从进程运行另一套代码。
1. 对等模式MPI程序设计
1.1 Jacobi 迭代
一句话概括就是矩阵每个元素都是其上下左右四个元素的平均值,矩阵四个边界的值不变。
1.2 用MPI程序实现Jacobi 迭代
将参加迭代的数据按列进行分割 并假设一共有4个进程同时并行计算。
进程0:A(M-1, 0 : N-1)
进程1:A(M-1, N : 2*N-1)
进程2:A(M-1, 2*N : 3*N-1)
进程3:A(M-1, 3*N : M-1)
由于在迭代过程中,边界点新值的计算需要相邻边界其它块的数据,因此在每一个数据块的两侧又各增加1列的数据空间,用于存放从相邻数据块通信得到的数据。这样原来每个数据块的大小从 M*N 扩大到 M*N+2,进程0和进程1的数据块只需扩大一块即可满足通信的要求, 但这里为了编程的方便和形式的一致,在两边都增加了数据块。
1. 对数组赋初值,边界赋为8,内部赋为0。
2. 每个进程都需要从相邻的进程得到数据块,同时每一个进程也都需要向相邻的进程提供数据块。注意:通信次序保证进程之间不会出现死锁。
3. 进行Jacobi迭代。
#include "mpi.h"
#include <stdio.h>
#define totalsize 16
#define mysize totalsize/4
#define steps 10
void main(int argc,char* argv[])
{
int myid,numprocs,n,i,j,rc;
float a[totalsize][mysize+2];
float b[totalsize][mysize+2]; //临时数组用来记录临时得到的新值
float temp[totalsize]; //进程间通信得到的数据
int begin_col,end_col,ierr;
MPI_Status status;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
fprintf(stderr,"Process %d of %d is alive.\n",myid,numprocs);
//初始化
for(j=0;j<mysize+2;j++)
for(i=0;i<totalsize;i++)
a[i][j]=0.0;
if(myid==0)
for(i=0;i<totalsize;i++)
a[i][1]=8.0;
if(myid==3)
for(i=0;i<totalsize;i++)
a[i][mysize]=8.0;
for(i=1;i<mysize+1;i++)
{
a[0][i]=8.0;
a[totalsize-1][i]=8.0;
}
//Jacobi 迭代
for(n=1;n<=steps;n++)
{
//从右侧邻居得到数据
if(myid<3)
{
MPI_Recv(&temp[0],totalsize,MPI_FLOAT,myid+1,10,MPI_COMM_WORLD,&status);
for(i=0;i<totalsize;i++)
a[i][mysize+1]=temp[i];
}
//向左侧邻居发送数据
if(myid>0)
{
for(i=0;i<totalsize;i++)
temp[i]=a[i][1];
MPI_Send(&temp[0],totalsize,MPI_FLOAT,myid-1,10,MPI_COMM_WORLD);
}
//向右侧邻居发送数据
if(myid<3)
{
for(i=0;i<totalsize;i++)
temp[i]=a[i][mysize];
MPI_Send(&temp[0],totalsize,MPI_FLOAT,myid+1,10,MPI_COMM_WORLD);
}
//从左侧邻居得到数据
if(myid>0)
{
MPI_Recv(&temp[0],totalsize,MPI_FLOAT,myid-1,10,MPI_COMM_WORLD,&status);
for(i=0;i<totalsize;i++)
a[i][0]=temp[i];
}
begin_col=1;
end_col=mysize;
if(myid==0)
begin_col=2;
if(myid==3)
end_col=mysize-1;
for(j=begin_col;j<=end_col;j++)
for(i=1;i<totalsize-1;i++)
b[i][j]=0.25*(a[i][j+1]+a[i][j-1]+a[i+1][j]+a[i-1][j]);
for(j=begin_col;j<=end_col;j++)
for(i=1;i<totalsize-1;i++)
a[i][j]=b[i][j]; //一次迭代完成后,统一进行更新
}
MPI_Barrier(MPI_COMM_WORLD);
fprintf(stderr,"\nProcess %d :\n",myid);
begin_col=1;
end_col=mysize;
for(i=0;i<totalsize;i++)
{
for(j=begin_col;j<=end_col;j++)