为什么MPI_Init之前的部分仍然是并行执行的
MPI_Init之前和MPI_Finalize之后的环境是串行的吗
背景
今天在进行MPI编程时,偶然发现MPI_Init之前和MPI_Finalize之后的部分实际上也是并行执行的.如下面的代码示例:
#include<stdio.h>
#include<mpi.h>
int main()
{
int *argc;
char ***argv;
int comm_sz,myrank;
printf("hello before init\n");
MPI_Init(argc,argv);
MPI_Comm_size(MPI_COMM_WORLD,&comm_sz);
MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
printf("hello from no.%d\n",myrank);
MPI_Finalize();
printf("hello after finalize\n");
return 0;
}
编译之后用8个进程运行,最终的结果是三种hello语句会各输出八条,而非我们直觉上认为的只有 hello from no.%d\n
会输出八条,这和我一开始看到的资料上的描述并不相符.
解决方案
在网上查找了一番之后最终找到了一个比较满意的答案:
https://stackoverflow.com/questions/47495108/cmpi-instruction-before-all-process-started
其大意为OpenMP和我们感觉上的流程相似,在并行环境初始化之前是串行的,并行的部分是通过多个线程join进来的方式实现并行,而MPI的机制则不尽相同,MPI的程序在用 mpirun -n 8
指定了进程数后,整个程序都会在多个核上进行,但是这样的执行只是一个核的动作的重复,也就是多个核执行同一段代码.而MPI的作用就是调度不同的任务给不同的核,实现并行计算.因此在MPI_Init之前和MPI_Finalize之后并不是串行环境,而是多核只能执行同一段代码的并行环境.
如何串行
那我们如何在一个mpi程序中加入串行的部分呢,在上面链接中的回答中已经有举例,感兴趣的可以自行查阅,其中最简单的方法就是将需要串行执行的代码段也放到MPI_Init之后的环境中,然后用 if(rank == 0)
的方式,指定某一个核执行相应的操作,变相地实现了串行.