gpt4 book ai didi

c++ - MPI 从属进程在没有更多工作时挂起

转载 作者:太空狗 更新时间:2023-10-29 20:16:07 35 4
gpt4 key购买 nike

我有一个要并行化的串行 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 还很陌生,所以请多多包涵。

谢谢

最佳答案

通常的做法是向所有工作进程发送一 strip 有特殊标记的空消息,以指示它们退出无限处理循环。假设这个标签是 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() 会反序列化执行并提高性能。然而,事实是您发送的消息非常小,并且这些消息通常在内部进行缓冲(警告 - 取决于实现!)所以您的 MPI_Send() 实际上是非阻塞的,您已经有非串行执行。 MPI_Isend() 返回您稍后需要处理的 MPI_Request 句柄。您可以使用 MPI_Wait()MPI_Waitall() 等待它完成,但您也可以在其上调用 MPI_Request_free()操作结束后会自动释放。当您想异步发送许多消息并且不关心发送何时完成时通常会这样做,但这是一个不好的做法,因为有大量未完成的请求会消耗大量宝贵的内存。至于工作进程 - 他们需要数据才能继续计算,因此不需要使用 MPI_Irecv()

欢迎来到 MPI 编程的精彩世界!

关于c++ - MPI 从属进程在没有更多工作时挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10490983/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com