MPI从进程挂在那里没有更多的工作时,(MPI Slave processes hang when

2019-06-24 05:42发布

我有一个串行C ++程序,我希望并行。 我知道MPI,基础知识MPI_SendMPI_Recv等,基本上,我有一个运行比数据处理算法显著更快的数据生成算法。 目前,他们在串联运行,但我想的是,在根进程中运行的数据的产生,具有在从进程所做的数据处理,并从根发送消息给包含数据的从属进行处理。 这样,每个从处理的数据集,然后等待它的下一个数据集。

问题是,一旦根过程完成产生数据,该程序挂起,因为从站正在等待更多。

这就是问题的一个示例:

#include "mpi.h"

#include <cassert>
#include <cstdio>

class Generator {
  public:
    Generator(int min, int max) : value(min - 1), max(max) {}
    bool NextValue() {
      ++value;
      return value < max;
    }
    int Value() { return value; }
  private:
    int value, max;

    Generator() {}
    Generator(const Generator &other) {}
    Generator &operator=(const Generator &other) { return *this; }
};

long fibonnaci(int n) {
  assert(n > 0);
  if (n == 1 || n == 2) return 1;
  return fibonnaci(n-1) + fibonnaci(n-2);
}

int main(int argc, char **argv) {
  MPI_Init(&argc, &argv);

  int rank, num_procs;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  MPI_Comm_size(MPI_COMM_WORLD, &num_procs);

  if (rank == 0) {
    Generator generator(1, 2 * num_procs);
    int proc = 1;
    while (generator.NextValue()) {
      int value = generator.Value();
      MPI_Send(&value, 1, MPI_INT, proc, 73, MPI_COMM_WORLD);
      printf("** Sent %d to process %d.\n", value, proc);
      proc = proc % (num_procs - 1) + 1;
    }
  } else {
    while (true) {
      int value;
      MPI_Status status;
      MPI_Recv(&value, 1, MPI_INT, 0, 73, MPI_COMM_WORLD, &status);
      printf("** Received %d from process %d.\n", value, status.MPI_SOURCE);
      printf("Process %d computed %d.\n", rank, fibonnaci(2 * (value + 10)));
    }
  }

  MPI_Finalize();
  return 0;
}

显然,以上并非一切都是“好习惯”,但它足以传达出点。

如果删除了while(true)从从属进程,然后当每个从站的已退出该程序退出。 我想程序退出后,才根进程已完成其工作,所有的奴隶都处理已发送的一切。

如果我知道怎么会产生许多数据集,我可以有很多进程在运行,一切都将很好地退出,但这里并非如此。

有什么建议? 有没有在API中任何会做到这一点? 难道这是解决了一个更好的拓扑结构比较好? 将MPI_IsendMPI_IRecv做得更好? 我是相当新的MPI所以多多包涵。

谢谢

Answer 1:

通常的做法是要发送到的所有工作进程与信号他们退出的无限循环处理特殊标记的空消息。 比方说,这个标签是42.你会做这样的事情在工人循环:

while (true) {
  int value;
  MPI_Status status;
  MPI_Recv(&value, 1, MPI_INT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
  if (status.MPI_TAG == 42) {
    printf("Process %d exiting work loop.\n", rank);
    break;
  }
  printf("** Received %d from process %d.\n", value, status.MPI_SOURCE);
  printf("Process %d computed %d.\n", rank, fibonnaci(2 * (value + 10)));
}

发电机循环之后的管理器进程会做这样的事情:

for (int i = 1; i < num_procs; i++)
  MPI_Send(&i, 0, MPI_INT, i, 42, MPI_COMM_WORLD);

关于你的下一个问题。 使用MPI_Isend()在主进程将deserialise执行和提高性能。 然而,事实是,你要发送很小的消息和那些通常内部缓冲( 警告! -依赖于实现的 ),所以您的MPI_Send()实际上是非阻塞的,你已经有非串行执行。 MPI_Isend()返回一个MPI_Request ,你需要采取的照顾后处理。 您既可以等待它完成与MPI_Wait()MPI_Waitall()但你也可以只调用MPI_Request_free()就可以了,它会在操作结束将自动释放。 这通常是当你想异步发送许多消息当发送将完成对不会在意,但它是一个不好的做法,但由于具有可消耗大量宝贵的内存的大量未完成的请求。 至于工作进程-他们需要的数据,以便与计算进行这样使用MPI_Irecv()是没有必要的。

欢迎到MPI编程的奇妙世界!



文章来源: MPI Slave processes hang when there is no more work