MPI串行主函数

14

这是一个相当基础的MPI问题,但我无法理解它。我有一个调用另一个使用MPI的函数的主函数。我希望主函数以串行方式执行,而其他函数以并行方式执行。我的代码如下:

int main (int argc, char *argv[])
{
    //some serial code goes here
    parallel_function(arg1, arg2);
    //some more serial code goes here
}

void parallel_function(int arg1, int arg2)
{
    //init MPI and do some stuff in parallel
    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &p);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
    //now do some parallel stuff
    //....
    //finalize to end MPI??
    MPI_Finalize();
}

我的代码运行良好并得到了预期的输出,但问题是主函数也在单独的进程中运行,因此串行代码执行了多次。我不知道它为什么会运行多次,因为我甚至还没有调用MPI_Init(如果在调用parallel_function之前在main中printf,我会看到多个printf)

我该如何在完成后停止程序并行运行?

感谢任何回复!

2个回答

10

@suszterpatt正确地指出了"MPI进程完全并行运行"。当您使用例如mpirunmpiexec运行并行程序时,它会启动您请求的进程数(使用-n标志),每个进程从main的开始处开始执行。因此,在您的示例代码中,

int main (int argc, char *argv[])
{
    //some serial code goes here
    parallel_function(arg1, arg2);
    //some more serial code goes here
}
每个进程都将执行//some serial code goes here//some more serial code goes here部分(当然它们都会调用parallel_function)。在调用MPI_Init之后,没有一个主进程会调用parallel_function并生成其他进程。

一般来说,最好避免做你正在做的事情:MPI_Init应该是程序中的第一个函数调用(理想情况下应该是第一个)。特别地,请注意以下内容(来源于这里):

  

MPI标准不会说明在MPI_INIT之前或MPI_FINALIZE之后程序能够做什么。在MPICH实现中,您应尽量少做这些操作。特别地,请避免更改程序的外部状态的任何操作,例如打开文件,读取标准输入或向标准输出写入内容。

不遵守此规则可能会导致一些恶性错误。

更好的做法是将您的代码重写为以下形式:

int main (int argc, char *argv[])
{

    // Initialise MPI
    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &p);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

    // Serial part: executed only by process with rank 0
    if (my_rank==0)
    {
        // Some serial code goes here
    }

    // Parallel part: executed by all processes.

    // Serial part: executed only by process with rank 0
    if (my_rank==0)
    {
        // Some more serial code goes here
    }

    // Finalize MPI
    MPI_Finalize();

    return 0;

}

注意:我不是C程序员,因此请谨慎使用上面的代码。另外,main函数作为int main()定义时,是否应该始终返回一些值呢?


1
每个进程都从main函数开始执行。技术上,它们从静态对象的初始化等操作开始。https://dev59.com/X2445IYBdhLWcg3w4-Be ;) - suszterpatt
1
当然,我过于追求细节了,但值得注意的是,静态对象的构造函数(可能是用户编写的)也会在main函数之前运行。这仅在MPI调用必须在此类构造函数中避免时才相关,即使MPI_Initmain函数的第一行。 - suszterpatt
@Chris,我能否将代码中的MPI部分放在一个单独的文件中(比如一个.DLL文件),并且有一个主C/C++文件来加载这个.DLL文件?我还想知道是否可以在不使用mpirunmpiexec的情况下运行MPI程序,并且可以通过任何其他系统传递消息(意思是MPI_Send(.. /特定于IP地址/)和MPI_Recv(/特定于IP/)? - programmer
@程序员 我不确定是否有这样的方法,但我会质疑为什么你想要这样做。我引用的MPI规范部分指出,在调用MPI_Init之前应尽可能少地执行操作,包括加载外部dll。至于你的第二个问题,我不知道,你需要查看这些函数的规范,以确定你想要做的是否可行。如果你有一个新问题,最好将其作为一个新问题发布,而不是作为旧问题或答案的评论。 - Chris
@Chris 谢谢。实际上我想创建一个等待请求的服务器。一旦收到请求,我想加载一个包含 mpi 相关代码的 dll 并并行执行。执行完成后读取值并发送响应。第二个问题我会另开一个问题。 - programmer
显示剩余2条评论

10
请看这个答案
简单来说,MPI_InitMPI_Finalize 并不标志着并行处理的开始和结束。MPI 进程在其全部运行期间都是并行执行的。

谢谢,现在更清楚了。我简直不敢相信我没有检查那个答案,我看了所有的MPI帖子。可能是因为它写着“Windows”,所以我忽略了它。 - Alex Aylwin
这并不完全正确。MPI标准没有规定init之前或finalize之后的状态。它可以是1个进程或n个进程。在实践中,所有现代实现都会给你n个进程,但也有一些托管实现不是这种情况。 - Jeff Hammond

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接