主从模式
所谓主从模式,就是MPI程序的各个进程所起的作用和地位并不相同,一个或者一些进程完成一类任务,而另外的进程完成其它的任务,这些功能或者地位不同的进程所对应的代码也有较大的差别。

矩阵向量乘
program main
include "mpif.h"
integer MAX_ROWS,MAX_COLS, rows, cols
parameter (MAX_ROWS=1000, MAX_COLS=1000)
double precision a(MAX_ROWS, MAX_COLS),b(MAX_COLS),c(MAX_COLS)
double precision buffer (MAX_COLS), ans

integer myid, master, numprocs, ierr, status(MPI_STATUS_SIZE)
integer i,j,numsent, numrcvd, sender
integer anstype, row

call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, myid, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numprocs, ierr)
master=0
rows=100
cols=100

if (myid .eq. master) then
C 主进程对矩阵A和B赋初值
do i=1,cols
b(i)=1
do j=1,rows
a(i,j)=i
end do
end do
numsent=0
numrcvd=0

C 将矩阵B发送给所有其它的从进程,通过下面的广播语句实现
call MPI_BCAST(b,cols,MPI_DOUBLE_PRECISION,master,
$ MPI_COMM_WORLD, ierr)

C 依次将矩阵A的各行发送给其它的numprocs-1个从进程
do i=1,min(numprocs-1,rows)
do j=1,cols

C将一行的数据取出来依次放到缓冲区中
buffer(j)=a(i,j)
end do

C将准备好的一行数据发送出去
call MPI_SEND(buffer, cols, MPI_DOUBLE_PRECISION,i,
$ i,MPI_COMM_WORLD, ierr)
numsent=numsent+1
end do
do i=1,row

C 对所有的行,依次接收从进程对一行数据的计算结果
call MPI_RECV(ans, 1,MPI_DOUBLE_PRECISION, MPI_ANY_SOURCE,
$ MPI_ANY_TAG,MPI_COMM_WORLD, status, ierr)
sender=status(MPI_SOURCE)
anstype=status(MPI_TAG)

C 将该行数据赋给结果数组C的相应单元
c(anstype)=ans
if (numsent .lt. rows) then

C 如果还有其它的行没有被计算,则继续发送
do j=1,cols
C准备好新一行的数据
buffer(j)=a(numsent+1,j)
end do

C 将该行数据发送出去
call MPI_SEND(buffer,cols, MPI_DOUBLE_PRECISION, sender,
$ numsent+1,MPI_COMM_WORLD, ierr)
numsent=numsent+1
else

C 若所有行都已发送出去,则每接收一个消息则向相应的从进程
C 发送一个标识为0的空消息,终止该从进程的执行
call MPI_SEND(1.0,0,MPI_DOUBLE_PRECISION,sender,
$ 0, MPI_COMM_WORLD, ierr)
end if
else

C下面为从进程的执行步骤,首先是接收数组B
call MPI_BCAST(b,cols,MPI_DOUBLE_PRECISION,master,
$ MPI_COMM_WORLD, ierr)

C接收主进程发送过来的矩阵A一行的数据
90 call MPI_RECV(buffer,cols, MPI_DOUBLE_PRECISION, master,
$ MPI_ANY_TAG, MPI_COMM_WORLD, status,ierr)

C 若接收到标识为0的消息,则退出执行
if (status(MPI_TAG) .ne. 0) then
row=status(MPI_TAG)
ans=0.0
do i=1,cols
ans=ans+buffer(i)*b(i)
end do

C计算一行的结果,并将结果发送给主进程
call MPI_SEND(ans, 1, MPI_DOUBLE_PRECISION, master, row,
$ MPI_COMM_WORLD, ierr)
goto 90
end if
endif
call MPI_FINALIZE(ierr)
end

讲解:

主进程将向量B广播给所有的从进程,然后将矩阵A的各行依次发送给从进程,从进程计算一行和B相乘的结果,然后将结果发送给主进程。主进程循环向各个从进程发送一行的数据,直到将A各行的数据发送完毕,一旦主进程将A的各行发送完毕,则每收到一个结果,就向相应的从进程发送结束标志,从进程接收到结束标志后退出执行。主进程收集完所有的结果后也结束。

矩阵向量乘