对等模式
所谓对等模式,就是说MPI程序的各个进程的功能、地位相同或相近, MPI程序的代码也应该是相近的,所不同的只是处理的对象和操作的数据,比如MPI程序让各个进程同时对一个数组的不同部分并行赋初值,各个进程间的关系就是典型的对等关系。
Jacobi叠代的实现
program main
implicit none
include 'mpif.h'
integer totalsize,mysize,steps
parameter (totalsize=16)
C 定义全局数组的规模
parameter (mysize=totalsize/4,steps=10)
integer n, myid, numprocs, i, j,rc
real a(totalsize,mysize+2),b(totalsize,mysize+2)
C 定义局部数组
integer begin_col,end_col,ierr
integer status(MPI_STATUS_SIZE)
call MPI_INIT( ierr )
call MPI_COMM_RANK( MPI_COMM_WORLD, myid, ierr )
call MPI_COMM_SIZE( MPI_COMM_WORLD, numprocs, ierr )
print *, "Process ", myid, " of ", numprocs, "
is alive"
C 数组初始化
do j=1,mysize+2
do i=1,totalsize
a(i,j)=0.0
end do
end do
if (myid .eq. 0) then
do i=1,totalsize
a(i,2)=8.0
end do
end if
if (myid .eq. 3) then
do i=1,totalsize
a(i,mysize+1)=8.0
end do
end if
do i=1,mysize+2
a(1,i)=8.0
a(totalsize,i)=8.0
end do
C Jacobi 迭代部分
do n=1,steps
C 从右侧的邻居得到数据
if (myid .lt. 3) then
call MPI_RECV(a(1,mysize+2),totalsize,MPI_REAL,myid+1,10,
*MPI_COMM_WORLD,status,ierr)
end if
C 向左侧的邻居发送数据
if ((myid .gt. 0) ) then
call MPI_SEND(a(1,2),totalsize,MPI_REAL,myid-1,10,
* MPI_COMM_WORLD,ierr)
end if
C 向右侧的邻居发送数据
if (myid .lt. 3) then
call MPI_SEND(a(1,mysize+1),totalsize,MPI_REAL,myid+1,10,
* MPI_COMM_WORLD,ierr)
end if
C 从左侧的邻居接收数据
if (myid .gt. 0) then
call MPI_RECV(a(1,1),totalsize,MPI_REAL,myid-1,10,
* MPI_COMM_WORLD,status,ierr)
end if
begin_col=2
end_col=mysize+1
if (myid .eq. 0) then
begin_col=3
endif
if (myid .eq. 3) then
end_col=mysize
endif
do j=begin_col,end_col
do i=2,totalsize-1
b(i,j)=(a(i,j+1)+a(i,j-1)+a(i+1,j)+a(i-1,j))*0.25
end do
end do
do j=begin_col,end_col
do i=2,totalsize-1
a(i,j)=b(i,j)
end do
end do
end do
do i=2,totalsize-1
print *, myid,(a(i,j),j=begin_col,end_col)
end do
call MPI_Finalize(rc)
end
为了并行求解,这里将参加迭代的数据按列进行分割,并假设一共有4个进程同时并行计算,数据的分割结果如下图所示。
图8-1 Jacobi迭代的数据划分及其与相应进程的对应

|
两边各增加1列,
用于存放通信得到
的数据 |
假设需要迭代的数据是M′M的二维数组A(M,M),令M=4*N,按图示进行数据划分,则分布在四个不同进程上的数据分别是:进程0,A(M,1:N),进程1,A(M,N+1:2*N),进程2,A(M,2*N+1:3*N),进程3,A(M,3*N+1:M)。
由于在迭代过程中,边界点新值的计算需要相邻边界其它块的数据,因此在每一个数据块的两侧又各增加1列的数据空间,用于存放从相邻数据块通信得到的数据。这样原来每个数据块的大小从M*N扩大到M*(N+2),进程0和进程1的数据块只需扩大一块即可满足通信的要求,但这里为了编程的方便和形式的一致,在两边都增加了数据块。
计算和通信过程是这样的,首先对数组赋初值,边界赋为8,内部赋为0,注意对不同的进程,赋值方式是不同的(两个内部块相同,但内部块和两个外部块两两互不相同)。然后便开始进行Jacobi迭代,在迭代之前,每个进程都需要从相邻的进程得到数据块,同时每一个进程也都需要向相邻的进程提供数据块(注意FORTRAN数组在内存中是按列优先排列的)。由于每一个新迭代点的值是由相邻点的旧值得到,所以这里引入一个中间数组,用来记录临时得到的新值,一次迭代完成后,再统一进行更新操作。
|