C 语言中的 MPI,所有处理器都在创建的 MPI 环境之外运行

计算科学 并行计算 C mpi
2021-12-22 19:24:54

我是 MPI 的新手,正在尝试找出其中的微妙之处,因此我只是在玩一个简单的例子。我的问题是,当我使用 2 个处理器运行下面的代码时,即使 printf 语句在 MPI_Init 之前,两个处理器都会打印它。无论如何都不会发生这种情况,并且只在环境初始化时使用多个处理器?下面是我的最小工作示例。

#include <mpi.h>
#include<stdio.h>

#define send_data_tag 2001
#define return_data_tag 2002

double add(int a);

int main(int argc, char ** argv)
{
  int rank, size, len;
  char host[MPI_MAX_PROCESSOR_NAME];

  printf("Will all processors print this?");
  MPI_Status status;
  MPI_Init(&argc, &argv);

  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  MPI_Comm_size(MPI_COMM_WORLD, &size);
  MPI_Get_processor_name(host, &len);

  if(rank == 0)
    {
        int test = 1;
        int final_test;
        MPI_Send(&test, 1 , MPI_INT, 1, send_data_tag, MPI_COMM_WORLD); 

        MPI_Recv(&final_test, 1, MPI_INT, 1, return_data_tag, MPI_COMM_WORLD, &status);
        printf("%d\n", final_test);
    }
  else
    {
        int test_recv , final_test;
        MPI_Recv( &test_recv, 1, MPI_INT, 0, send_data_tag, MPI_COMM_WORLD, &status);
        final_test = test_recv + 1;
        MPI_Send(&final_test, 1, MPI_INT, 0, return_data_tag, MPI_COMM_WORLD);
    }


MPI_Finalize();
}
3个回答

我担心你会混淆你的平行范式。MPI 支持通过网络相互通信的多个进程(想想程序的实例)的并行性。“网络”可能位于一个盒子内,也可能位于相距数英里的多台机器上。考虑到这一点,很容易看出为什么您的打印命令会被多次运行。每个单独的进程启动,打印字符串,然后实际开始建立与其他进程的通信。因此,将 IO 限制为一个进程的唯一方法是使用诸如if (rank==0).

另一个并行模型,线程,在单个进程中的单个盒子上工作,线程共享对同一内存的访问。该模型更适合您描述的观点,即仅在需要并行完成工作时才创建线程。如果您对此感兴趣,请查看有关OpenMP的一些教程(不要与 openMPI 混淆,这是一种众所周知的 MPI 实现),这似乎是目前最流行的以最少工作量线程化程序的方式。

通常,在 MPI 程序中MPI_Init()MPI_Comm_rankMPI_Comm_size在一开始只使用一次。它们初始化环境,分配“等级”并在通信器中获取通信器大小MPI_COMM_WORLD(在某些情况下,为了方便,可以设置多个通信器)。但是你的问题仍然很有趣。

使用 MPI 编译并运行这个小代码:

#include<stdio.h>
#include <unistd.h>

int main(int argc, char ** argv)
{
  printf("Will all processors print this?\n"
          "My process ID : %d\n"
          "My parent's ID: %d\n",
          getpid(),getppid());
}

这将打印您从 mpirun 启动的每个进程的 ID,以及父进程。

请注意,这里甚至没有mpi.h包含 。您看到的是因为您使用 mpirun 启动了多个进程。它们中的每一个都获得相同的二进制文件,但可以遵循不同的分支,因为 MPI 为其分配了不同的分支rank

如果你只想用一个进程做某事,你必须把它放在一个if (rank==0)(或类似的语句)中,就像 origimbo 提到的那样。当然,这需要在MPI_Init()MPI_Comm_rank()调用之后。

如果那是您真正想要的,则可以使用 MPI_COMM_SPAWN(...)( 以及更通用的 MPI_COMM_SPAWN_MULTIPLE(...))。它可用于启动第二个(单独的)MPI 程序并与之通信。您必须将代码分成两部分,初始串行部分,然后是由 MPI_COMM_SPAWN(...) 启动的后续并行部分