第一个例子: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)
!!!说明!!!
  BUF   -- 发送缓冲区的起始地址(可选类型),就是需要发送什么数据
  COUNT -- 将发送的数据的个数(非负整数)
  DATATYPE -- 发送数据的数据类型(句柄),就是发送的数据的类型,比如 MPI_INTEGER,MPI_CHAR 等
  DEST  -- 目的进程标识号(整型),就是要把数据发给谁(发给哪个进程)
  TAG   -- 消息标志(整型),区分此进程项同意目的进程发送的其他消息
  COMM  -- 通信域
  IERROR   -- 返回的错误代码

说明:MPI_SEND将发送缓冲区中的count个datatype数据类型的数据发送到目的进程,目的进程在通信域中的标识号是dest,本次发送的消息标志是tag,使用这一标志,就可以把本次发送的消息和本进程向同一目的进程发送的其它消息区别开来。

 

MPI_RECV,消息接收

MPI_RECV(BUF, COUNT, DATATYPE, SOURCE, TAG, COMM, STATUS, IERROR)
!!!说明!!!
  BUF      -- 接受缓冲区的起始地址(可选类型),就是需要接收什么数据
  COUNT    -- 最多可接收的数据的个数(非负整数)
  DATATYPE -- 接收数据的数据类型(句柄),就是接收的数据的类型,比如 MPI_INTEGER,MPI_CHAR 等
  SOURCE   -- 接收数据的来源即发送数据的进程的进程标识号(整型),就是要从哪个进程接收数据
  TAG      -- 消息标识 与相应的发送操作的表示相匹配相同(整型)
  COMM     -- 通信域
  STATUS   -- 返回状态 (状态类型)
  IERROR   -- 返回的错误代码

说明:MPI_RECV从指定的进程source接收消息,并且该消息的数据类型和消息标识和本接收进程指定的datatype和tag相一致,接收到的消息所包含的数据元素的个数最多不能超过count。

status 是包含 MPI_STATUS_SIZE 个整型的数组,status(MPI_SOURCE),status(MPI_TAT)和status(MPI_ERROR)分别表示发送数据的进程标识,发送数据使用tag标识和该接收操作返回的错误代码。所以在定义时,status被定义为一个为数组。
 

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同步命令。下一篇博文会介绍。

 

posted @ 2020-09-14 09:40  cfdchen  阅读(1914)  评论(0编辑  收藏  举报