MPI库并行Fortran程序:进程通讯
用MPI库并行Fortran程序时,常常需要进程通讯以实现数组同步。这里的一个简单的例子可以说明MPI_SEND命令和MPI_RECV命令的用法,以实现点到点的通讯。
并行的目的
为什么要并行?
并行主要是为了将大型循环分摊到不同的CPU上,以节约时间。
最简单的例子
用三个进程分摊10次循环,为A(10)数组分别赋值1-10,最后三个进程相互通讯,把每个进程里的A(10)数列同步。
如何用多个CPU分摊循环?
三个CPU的进程编号分别为0,1,2。
进程0承担第3,6,9次循环。
进程1承担第1,4,7,10次循环。
进程2承担第2,5,8次循环。
最后三个进程相互通讯,把本进程里运算的结果也分享给其他CPU,即数列同步。
方法1:点对点通讯
MPI_SEND和MPI_RECV命令只针对两个进程之间。即一个进程接收,一个进程发送。
如果一个进程要发送给其他的2个进程的数据,需要发送2次,分别指定不同的终点和暗号。
如果一个进程要接收其他两个2个进程的数据,需要接收2次,分别指定不同的起点和暗号。
MPI_SEND命令
CALL MPI_SEND(buffer,count,datatype,destination,tag,comm,ierror)
该命令会将本进程里的buffer(count)数组或者变量发送到destination进程中,通讯“暗号”为tag,暗号一致即可通讯。详细选项如下:
buffer
数组或整形,实数都可。为待发送的数组或者变量名。
count
整形。为待发送数据的长度,单个变量的长度为1。
datatype
为以下选择中的1个:
MPI DATATYPE | Fortran DATATYPE |
---|---|
MPI_CHARACTER | character(1) |
MPI_INTEGER | integer |
MPI_REAL | real |
MPI_DOUBLE_PRECISION | double precision,适合REAL(kind=8) |
MPI_COMPLEX | complex |
MPI_LOGICAL | logical |
MPI_BYTE | 8 binary digits |
destination
整形。为发送目的地的进程编号。
tag
整形。为通讯标识,当接收和发送的通讯标识一致时才会进行收发,否则会等待下去。
comm
通信器,一般使用系统预先定义的全局通信因子“MPI_COMM_WORLD”。
ierror
输出。如果执行成功则会返回0。
MPI_RECV命令
CALL MPI_RECV(buffer,count,datatype,source,tag,comm,status,ierror)
该命令会将接收来自source进程里的buffer(count)数组或者变量,通讯“暗号”为tag,暗号一致即可通讯。详细选项如下:
buffer
数组或整形,实数都可。为接收的数组或者变量名。
count
整形。为接收数据的长度,单个变量的长度为1。
datatype
同MPI_SEND命令。
source
整形。为发送来源地的进程编号。
tag
整形。为通讯标识,要与MPI_SEND命令中的通讯标识一致。
comm
通信器,一般使用系统预先定义的全局通信因子“MPI_COMM_WORLD”。
status
输出。0表示还未收到。
ierror
输出。如果执行成功则会返回0。
示例程序
文件test_mpi.f程序如下
cloc
program test_mpi
USE MPI
INTEGER:: ICORE,NCORE,IERR,MASTER
DIMENSION::A(10)
DATA A/0,0,0,0,0,0,0,0,0,0/
C INITIALIZATION
CALL MPI_INIT(IERR)
CALL MPI_COMM_RANK(MPI_COMM_WORLD,ICORE,IERR)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD,NCORE,IERR)
MASTER = 0
IF(ICORE.EQ.MASTER) WRITE(6,'(I3,"-CORES ASSIGNED")') NCORE
CALL MPI_BARRIER(MPI_COMM_WORLD,IERR)
C INPUT DATA 单个进程为各自的部分赋值
DO I = 1,10
ICE = MOD(I,NCORE)
IF(ICE.EQ.ICORE) A(I)=1.0*I
ENDDO
C COMMUNICATION 进程通讯,以同步变量
DO 1 J = 1,10
ICE = MOD(J,NCORE)
IF(ICE.EQ.ICORE) THEN
TMP = A(J)
!在NCORE个进程中,只有第ICE个进程被赋值,它要将该值发送给剩下的NCORE-1个进程
DO I = 0,NCORE-1
IF (I.NE.ICE) CALL MPI_SEND(TMP,1,MPI_REAL,I,
& I,MPI_COMM_WORLD,IERR)
ENDDO
ELSE
!每个进程分别接收来自ICE个进程发送来的数据,通讯标识号为自己的进程号
CALL MPI_RECV(TMP,1,MPI_REAL,
& ICE,ICORE,MPI_COMM_WORLD,ISTATUS,IERR)
A(J) = TMP
ENDIF
1 CONTINUE
C OUTPUT DATA 输出进程0同步后的变量
WRITE(6,'(I2,10F5.1)') ICORE,(A(I),I=1,10)
CALL MPI_FINALIZE(IERR)
end program
运行test_mpi.f程序
mpiifort -g test_mpi.f -o z #编译
mpirun -np 3 ./z #运行
mpirun -np 3 xterm -e gdb ./z #用GDB调试程序
运行结果,输出为:
3-CORES ASSIGNED
0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0
1 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0
2 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0
方法2:通过广播同步变量
MPI_BCAST命令可以将一个进程里的某个变量或数组同步到所有进程中。
MPI_BCAST命令
CALL MPI_BCAST(buffer,count,datatype,root,comm,ierror)
该命令是将进程root中的buffer(count)数组或变量同步到其他所有进程中。注意只有出现该命令的进程才会接收广播。
buffer
数组或整形,实数都可。为广播发出和收听的数组或者变量名。
count
整形。为广播发出和收听数据的长度,单个变量的长度为1。
datatype
同MPI_SEND或MPI_RECV命令。
root
整形。广播发出的进程编号。如果root等于本进程号,则buffer既发出也接收;如果root不等于本进程编号,则本进程的buffer会接收广播发出的buffer。
comm
通信器,一般使用系统预先定义的全局通信因子“MPI_COMM_WORLD”。
ierror
输出。如果执行成功则会返回0。
广播示例
文件test_mpi.f如下
cloc
program test_mpi
USE MPI
INTEGER:: ICORE,NCORE,IERR,MASTER
DIMENSION::A(10)
DATA A/0,0,0,0,0,0,0,0,0,0/
C INITIALIZATION
CALL MPI_INIT(IERR)
CALL MPI_COMM_RANK(MPI_COMM_WORLD,ICORE,IERR)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD,NCORE,IERR)
MASTER = 0
IF(ICORE.EQ.MASTER) WRITE(6,'(I3,"-CORES ASSIGNED")') NCORE
CALL MPI_BARRIER(MPI_COMM_WORLD,IERR)
C INPUT AND BCAST DATA
DO I = 1,10
ICE = MOD(I,NCORE)
!单个进程为数组A(10)中各自的部分赋值
IF(ICE.EQ.ICORE) THEN
A(I) = 0.1+I*1.0
ENDIF
!赋值之后马上广播出去,将数组A(10)从ICE进程广播到其他进程中,以实现各个进程中的A数组同步
CALL MPI_BCAST(A,10,MPI_REAL,ICE,MPI_COMM_WORLD,IERR)
ENDDO
C OUTPUT DATA
WRITE(6,'(I2,10F5.1)') ICORE,(A(I),I=1,10)
CALL MPI_FINALIZE(IERR)
end program
运行test_mpi.f程序
mpiifort -g test_mpi.f -o z #编译
mpirun -np 3 ./z #运行
mpirun -np 3 xterm -e gdb ./z #用GDB调试程序
运行结果,输出为:
3-CORES ASSIGNED
0 1.1 2.1 3.1 4.1 5.1 6.1 7.1 8.1 9.1 10.1
1 1.1 2.1 3.1 4.1 5.1 6.1 7.1 8.1 9.1 10.1
2 1.1 2.1 3.1 4.1 5.1 6.1 7.1 8.1 9.1 10.1
本文来自博客园,作者:Philbert,转载请注明原文链接:https://www.cnblogs.com/liangxuran/p/17105653.html