- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个要并行化的串行 C++ 程序。我了解 MPI 的基础知识,MPI_Send
、MPI_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_Isend
或 MPI_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/
我正在使用 Gunicorn 为 Django 应用程序提供服务,它工作正常,直到我将其超时时间从 30 秒更改为 900000 秒,我不得不这样做,因为我有一个用例需要上传和处理一个巨大的文件(过程
我有一个带有非常基本的管道的Jenkinsfile,它可以旋转docker容器: pipeline { agent { dockerfile { args '-u root' } } stag
在学习 MEAN 堆栈的过程中,我遇到了一个问题。每当我尝试使用 Passport 验证方法时,它都不会返回任何响应。我总是收到“localhost没有发送任何数据。ERR_EMPTY_RESPONS
在当今的大多数企业堆栈中,数据库是我们存储所有秘密的地方。它是安全屋,是待命室,也是用于存储可能非常私密或极具价值的物品的集散地。对于依赖它的数据库管理员、程序员和DevOps团队来说,保护它免受所
是否可以创建像图片上那样的边框?只需使用 css 边框属性。最终结果将是没 Angular 盒子。我不想添加额外的 html 元素。我只想为每个 li 元素添加 css 边框信息。 假设这是一个 ul
我是一名优秀的程序员,十分优秀!