【问题标题】:When should I terminate MPI child processes?我应该何时终止 MPI 子进程?
【发布时间】:2014-04-15 00:20:25
【问题描述】:

我正在使用 MPI 在 C++ 中实现一个算法。有许多文件需要处理。这是我的设计:

int main()
{
  MPI_Init();
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
  MPI_Comm_rank(MPI_COMM_WORLD, &nproc);

  MPI_Barrier(..);
  if(my_rank == 0)
  {
    for (each file to be processed)
      {
         Read in file content;
         MPI_Send data to child processes;
         process partial data on root process;
         MPI_Recv data processed by child processes;
         combine processed data from root and children;
      }
   }
   else
   {
      MPI_Recv data from root;
      process received data;
      MPI_Send processed data to root;
      MPI_Finalize();
    }

//only root process reaches here
MPI_Finalize();

}

当只有一个文件要处理时,程序运行完美。但是,如果我有超过 1 个文件要处理,它将停留在第二个文件中。而且似乎没有子进程可用于从根接收新数据。我认为这是因为我在处理第一个文件后终止了子进程。但是如果我在 else 块中注释掉 MPI_Finalize() ,程序将在处理第一个数据文件后退出,并出现错误:

mpirun has exited due to process rank 1 with PID 2003 on
node c301-115 exiting improperly. There are three reasons this could occur:

1. this process did not call "init" before exiting, but others in
the job did. This can cause a job to hang indefinitely while it waits
for all processes to call "init". By rule, if one process calls "init",
then ALL processes must call "init" prior to termination.

2. this process called "init", but exited without calling "finalize".
By rule, all processes that call "init" MUST call "finalize" prior to
exiting or it will be considered an "abnormal termination"

3. this process called "MPI_Abort" or "orte_abort" and the mca parameter
orte_create_session_dirs is set to false. In this case, the run-time cannot
detect that the abort call was an abnormal termination. Hence, the only
error message you will receive is this one. 

在这种情况下,有没有办法为子进程重置 MPI 实例?在哪里完成子进程的最佳位置?

【问题讨论】:

  • MPI_Finalize 不会导致程序退出。您的工作进程实际上会调用该函数两次,这可能会产生意想不到的结果。

标签: c++ mpi


【解决方案1】:

您需要第二个 for 循环让工作人员等待新的分配,这样他们就不会立即终止。

这样想:你有 N 个人同时工作。你不知何故决定,其中一个名字为“0”的人有一项特殊的工作,即为所有其他人分配工作。你给出了每个人都应该做什么的准确规范。你写的代码在你的代码中看起来是这样的,这意味着

for(file in files)
   send job

对于名字为“0”的人

process one job

对于所有其他人。你希望其他人做的是:

for(file in files)
   process job

这应该反映在您的代码中,可能类似于:

int main()
{
  MPI_Init();
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
  MPI_Comm_rank(MPI_COMM_WORLD, &nproc);

  MPI_Barrier(..);
  if(my_rank == 0)
  {
    for (each file to be processed)
      {
         Read in file content;
         MPI_Send data to child processes;
         process partial data on root process;
         MPI_Recv data processed by child processes;
         combine processed data from root and children;
      }
   }
   else
   {
      for (each file to be processed)
        {
          MPI_Recv data from root;
          process received data;
          MPI_Send processed data to root;
          MPI_Finalize();
        }
    }

  //only root process reaches here
  MPI_Finalize();
}

旁注:您提议的极端等级结构有什么好处?如果每个工作线程都在自己的文件上工作不是更好吗?

【讨论】:

  • 如果数据处理功能是串行的,那么同时处理多个文件是完全可以的。但在我的例子中,函数本身是用 MPI 实现的。
  • 根进程中的 for 循环更有意义,因为它每次迭代都会读取一个文件。但是,子进程不直接处理文件。他们所做的只是从根接收数据,处理并将数据发送回根。所以分解成几个迭代会有点棘手。换句话说,for 循环中的 i 或 root 不一定映射到 for 子循环中的 i。
  • 还有比for循环更好的策略吗?
  • @MrWhite 您可以将if 放在for 循环中。这将更清楚地表明根和工作人员 同步 正如 hammar 所说的那样
【解决方案2】:

请记住,您的流程需要保持“同步”。也就是说,对于每个发送都应该有一个接收等等,因此您需要在子进程中拥有一个循环,就像在根进程中一样。

这样做的一种方法是在程序开始时,让根进程将要处理的文件数发送给所有子进程。然后让它们像根进程一样循环。

【讨论】:

  • 我想关于我的算法的一些背景可能会有所帮助。我正在尝试使用 MPI 实现递归合并排序算法,该算法将应用于外部排序。这就是为什么我可以一次将整个文件读入内存的原因。根进程将要排序的数组分成两半,左半部分将由同一进程处理,而右半部分将被发送到子进程并在那里排序。一旦在子进程上排序,那一半将被发送回根并与在同一进程上排序的另一半合并。 (待续)
  • (继续..)在我的主函数中,对于 rank==0 和 else 块,我的主排序函数 mergesort_mpi 将被调用。根据进程的等级和可用的处理器数量,程序将决定是对分配的数组进行排序还是进行下一次迭代。在我的 mergesort_mpi 函数中,有 MPI_Send 和 MPI_Recv 命令。总体而言,发送匹配接收。
  • 我想我的问题是。如果我有另一个子进程的for循环,我如何确保子进程正在从根进程的for循环中i定义的相应数据集中接收数据?
  • @MrWhite:只要两个进程的发送和接收操作顺序相同,一切都很好。但是如果你想确定,你可以将i作为MPI_Send/Recv的tag参数传递。
猜你喜欢
  • 2011-01-21
  • 1970-01-01
  • 2011-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多