第一个例子:MPI最常用的6个调用说明,以"Hello_World.f90"为例
MPI Massage Passing Interface. 一旦完成初始化,在结束MPI之前,除非特别指定,每个进程都会完全一致地执行相同的命令。
在MPI中有上百个调用接口,但是最常用的只有几个,掌握这几个调用的用法,就可以快速上手并行计算编程了。一旦入门,之后的学习就会简单许多。
!!!!!!!!!
MPI_INIT MPI_COMM_RANK MPI_COMM_SIZE MPI_SEND MPI_RECV MPI_FINALIZE
!!!!!!!!!
头文件
1 use mpi
Fortran90使用 use mpi 加载MPI头文件。
MPI_INIT,并行环境MPI初始化。
MPI_INIT(ierr)
!!!说明!!!
MPI初始化后,返回一个错误代码 ierr。这个ierr在定义变量的时候,也要定义
说明:MPI程序的第一个调用,完成MPI的初始化工作,所有MPI程序的第一条可执行语句都是这个。一旦完成初始化,在结束MPI之前,除非特别指定,每个进程都会完全一致地执行相同地命令。比如10行,11行,和13行,这些命令所有的进程都会执行一遍,因此,在运行程序后,会看到屏幕上有4行write的内容。但是如果有特别指定,比如17行if判断,只有符合条件的进程才会执行if内的命令。
MPI_COMM_RANK,当前进程标识。
MPI_COMM_RANK(COMM,RANK,IERROR)
!!!说明!!!
COMM -- 该进程所在的通信域,定义在该通信域中的进程processor都在该通信域中通信。不同的通信域有不同的名称
RANK -- 调用进程processor在COMM通信域中的标识号,意思就是给不同的进程都取名字,比如用4个核并行计算,那么名字就是0,1,2,3,从0开始标记,并且一般把0,也就是第一个进程看作主进程
IERROR -- 和上边的ierr一样,都是返回的错误代码
说明:这一调用返回调用进程在给定的通信域中的进程标识号,有了这一标识号,不同的进程就可以将自身和其它的进程区别开来,实现各进程的并行和协作。
MPI_COMM_SIZE,通信域包含的进程数
MPI_COMM_SIZE(COMM,SIZE,IERROR)
!!!说明!!!
COMM -- 通信域
SIZE -- 该通信域COMM中总共有多少个进程,就是用了多少个核并行计算
IERROR -- 返回的错误代码
说明:这一调用返回给定的通信域中所包括的进程的个数,不同的进程通过这一调用得知在给定的通信域中一共有多少个进程在并行执行。
MPI_SEND,消息发送
MPI_SEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, IERROR)
!!!说明!!!
说明:MPI_SEND将发送缓冲区中的count个datatype数据类型的数据发送到目的进程,目的进程在通信域中的标识号是dest,本次发送的消息标志是tag,使用这一标志,就可以把本次发送的消息和本进程向同一目的进程发送的其它消息区别开来。
MPI_RECV,消息接收
MPI_RECV(BUF, COUNT, DATATYPE, SOURCE, TAG, COMM, STATUS, IERROR)
!!!说明!!!
说明:MPI_RECV从指定的进程source接收消息,并且该消息的数据类型和消息标识和本接收进程指定的datatype和tag相一致,接收到的消息所包含的数据元素的个数最多不能超过count。
MPI_FINALIZE,并行环境MPI结束
MPI_FINALIZE(IERROR)
!!!说明!!!
IERROR -- 返回的错误代码
说明:MPI_FINALIZE是MPI程序的最后一个调用,它结束MPI程序的运行,它是MPI程序的最后一条可执行语句,否则程序的运行结果是不可预知的。
例:Hello_World.f90
1 program main 2 3 use mpi 4 implicit none 5 6 character(len=20) :: message1,message2,message3 7 integer :: myid, ierr, status(mpi_status_size), rc, numprocs 8 9 call MPI_INIT(ierr) 10 call MPI_COMM_RANK( MPI_COMM_WORLD, myid, ierr ) 11 call MPI_COMM_SIZE(MPI_COMM_WORLD,numprocs,ierr) 12 write(*,*) ' process ', myid, ' of ', numprocs, ' is alive' 13 14 if ( myid .eq. 0) then 15 message1 = 'Hello, process 1' 16 call MPI_SEND(message1,20,MPI_CHAR,1,99,MPI_COMM_WORLD,ierr) 17 message2 = 'Hello, process 2' 18 call MPI_SEND(message2,20,MPI_CHAR,2,99,MPI_COMM_WORLD,ierr) 19 message3 = 'Hello, process 3' 20 call MPI_SEND(message3,20,MPI_CHAR,3,99,MPI_COMM_WORLD,ierr) 21 else if ( myid .eq. 1 ) then 22 call MPI_RECV(message1,20,MPI_CHAR,0,99,MPI_COMM_WORLD,status,ierr) 23 write(*,*) message1 24 else if ( myid .eq. 2 ) then 25 call MPI_RECV(message2,20,MPI_CHAR,0,99,MPI_COMM_WORLD,status,ierr) 26 write(*,*) message2 27 else if ( myid .eq. 3 ) then 28 call MPI_RECV(message3,20,MPI_CHAR,0,99,MPI_COMM_WORLD,status,ierr) 29 write(*,*) message3 30 end if 31 32 call MPI_FINALIZE(rc) 33 34 end
编译:mpif77和mpif90分别编译并联接用FORTRAN77和Fortran90编写的MPI程序,在这里,用mpif90进行编译。(这里mpifort也可以编译f90程序)
1 mpif90 Hello_World.f90 -o Hello_World.out ! 或者 mpifort Hello_World.f90 -o Hello_World.out
执行:用mpirun来执行并行计算程序,mpirun –np N program 或者 mpirun –n N program,N 是指定多少个进程同时运行,即多少核并行计算。
1 mpirun -n 4 Hello_World.out ! 或者 mpirun -np 4 Hello_World.out
程序执行结果:
1 process 0 of 4 is alive 2 process 1 of 4 is alive 3 process 2 of 4 is alive 4 Hello, process 2 5 Hello, process 1 6 process 3 of 4 is alive 7 Hello, process 3
可以看到,12行的write命令被执行了4次,但是这4次并不连续,因为21行之后的if判断抢了先。不同的进程,执行速度不太一样,有快有慢,就造成了如上的结果。要想让12行的write命令,4个进程都执行完,才执行之后的命令,要用到MPI_BARRIER同步命令。下一篇博文会介绍。