目录
一、Fortran 90 +MPI实现
二、C++ +MPI实现
三、MPI程序的一些惯例
四、小结
相信许多编程初学者的入门程序都是“Hello World”,我们同样来编写MPI的第一个程序“Hello World”。
一、Fortran 90 +MPI实现
我们先给出代码,然后进行代码分析。
program main
include 'mpif.h'
character *(MPI_MAX_PROCESSOR_NAME) processor_name
integer myid, numprocs, namelen, rc, ierr
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, myid, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numprocs, ierr)
call MPI_GET_PROCESSOR_NAME(processor_name, namelen, ierr)
write(*,10) myid, numprocs, processor_name
10 FORMAT("Hello World! Process",I2," of ",I1 " on ",20A)
call MPI_FINALIZE(rc)
end
代码解析:
①首先要包含MPI相对于Fortran实现的头文件mpif.h,这与MPI相当于C语言的实现是不同的。现在MPI的实现已经支持Fortran 90+MPI,在MPI-2中明确了对Fortran 90和C++的支持。如果是Fortran 90程序,则需要将“include mpif.h”改为“use mpi”,也就是说MPI被定义为一个Fortran 90 调用的模块。
②定义程序中所需要的与MPI有关的变量。MPI_PROCESSOR_NAME是MPI预定义的宏,即某一MPI的具体实现中允许机器名字的最大长度,机器名存放在变量processor_name中。整型变量myid和numprocs分别用来存储某一并行执行的进程的标识和所有参加计算的进程的个数。namelen是实际得到的机器名字的长度。rc和ierr分别用来得到MPI过程调用结束后返回结果和可能出现的错误信息。
③MPI程序的开始和结束必须是MPI_INIT和MPI_FINALIZE,分别完成MPI程序的初始化和结束工作。
④MPI程序的主体,包括MPI过程调用语句和Fortran语句。MPI_COMM_RANK得到当前正在运行的进程标识号,存放在变量myid中。MPI_COMM_SIZE得到所有参加计算的进程的个数,存放在变量numprocs中。MPI_GET_PROCESSOR_NAME得到运行本进程的机器名称,存放在变量processor_name中,是一个字符串,长度存放在namelen中。write语句是普通的Fortran语句,将本进程的标识号、进程个数、运行进程的机器名字打印出来,和一般的Fortran程序不同的是这些程序体中的执行语句是并行执行的,每一个参与的进程都要执行。
程序编译采用mpif90编译器,方式如下:
mpif90 test1.f90 -o test1
执行命令为:
mpirun -np 4 ./test1
执行结果为:
这里采用4个进程并行执行Hello world程序,4个进程都运行在同一台机器上,标识号分别为0、1、2、3,每个进程都执行一次程序,所以最终的执行结果有四条打印语句。
执行流程如下:
二、C++ +MPI实现
代码如下:
#include "mpi.h"
#include <stdio.h>
#include <math.h>
int main(int argc, char *argv[])
{
int myid, numprocs, namelen;
char processor_name[MPI_MAX_PROCESSOR_NAME];
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
MPI_Get_processor_name(processor_name, &namelen);
printf("Hello World! Process %d of %d on %s.\n", myid, numprocs, processor_name);
MPI_Finalize();
return 0;
}
C++ + MPI并行程序结构和Fortran 90 + MPI的完全相同,只是在接口调用上的形式和语法有所区别。
代码解析:
①首先要包含MPI头文件'mpi.h',而不是‘mpif.h’。
②定义程序中与MPI有关的变量。这里和Fortran 90程序中定义的变量含义相同。
③MPI开始和结束的语句是MPI_Init和MPI_Finalize。对比Fortran程序,这两个函数调用时的参数不同,习惯上,Fortran 90中所有MPI调用均为大写(Fortran程序对大小写无关),在C++中是以“MPI_”开头,后面部分的第一个字母大写,其后续部分为小写。
程序编译采用mpicxx编译器,方式如下:
mpicxx test1.cpp -o test1_cxx
执行命令为:
mpirun -np 4 ./test1_cxx
执行结果为:
从上面的两个例子可知,一个MPI程序的框架结构大概为:
三、MPI程序的一些惯例
Fortran程序中的MPI调用一般全为大写,C/C++程序中的MPI调用为MPI_Aaaa_aaaa的形式。所有MPI的Fortran子程序在最后参数中都有一个返回代码,对于成功,返回的是MPI_SUCCESS,其它的错误代码是依赖于实现的。一些MPI操作是函数,没有返回代码参数。
Fortran中的句柄以整型表示,二值变量是逻辑类型。Fortran的数组下标是从1开始,C/C++是从0开始。
四、小结
从上述介绍和两个例子可知,MPI是在原来的串行程序上进行扩展,其许多地方和串行程序是相同的。串行程序设计的许多经验也是可以应用到并行程序设计中,但是在设计并行程序时,我们需要时刻明确程序并行执行的概念,而不是原来有序的串行执行,这是串行和并行的最主要区别。