MPI轻量任务分发程序异常排查:为何仅输出前两行?
问题分析:MPI任务分发程序无法持续输出任务结果
我正在自学基础MPI,写了一个向工作节点分发轻量任务的练习程序——任务仅让CPU等待预设时长,目标是验证工作节点完成当前任务后会立即请求新任务,不用等其他节点。
在1个管理节点+2个工作节点(共3个CPU)的环境下,预期输出示例:
worker #1 waited for 1 seconds
worker #2 waited for 1 seconds
worker #1 waited for 1 seconds
worker #1 waited for 1 seconds
...
worker #2 waited for 5 seconds
worker #1 waited for 1 seconds
worker #2 waited for 1 seconds
...
但现在程序只能输出前两行,之后就没内容了。推测是工作节点没正确反馈任务完成状态,没法获取新任务。
当前代码实现:
#include <iostream> #include <mpi.h> #include <windows.h> using namespace std; void task(int waittime, int worldrank) { Sleep(waittime); // use sleep for unix systems cout << "worker #" << worldrank << " waited for " << waittime << " seconds" << endl; } int main() { int waittimes[] = { 1,1,5,1,1,1,1,1,1,1,1,1,1 }; int nwaits = sizeof(waittimes) / sizeof(int); MPI_Init(NULL, NULL); int worldrank, worldsize; MPI_Comm_rank(MPI_COMM_WORLD, &worldrank); MPI_Comm_size(MPI_COMM_WORLD, &worldsize); MPI_Status status; int ready = 0; if (worldrank == 0) { for (int k = 0; k < nwaits; k++) { MPI_Recv(&ready, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); MPI_Send(&waittimes[k], 1, MPI_INT, status.MPI_SOURCE, 0, MPI_COMM_WORLD); } } else { int waittime; ready = 1; MPI_Send(&ready, 1, MPI_INT, 0, 0, MPI_COMM_WORLD); MPI_Recv(&waittime, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status); task(waittime,worldrank); } MPI_Finalize(); return 0; }
问题根源
工作节点代码只执行了一次任务请求-执行流程就直接退出了,没有循环处理后续任务。管理节点的循环会等待所有任务的就绪请求,但工作节点完成第一个任务后就调用MPI_Finalize()终止进程,导致管理节点卡在MPI_Recv步骤等待后续信号,程序因此停滞。
修复方案
给工作节点添加循环逻辑,让它们完成任务后持续向管理节点发送就绪信号;同时管理节点在分发完所有任务后,向工作节点发送终止信号,通知它们退出循环。
修改后的工作节点代码
else { int waittime; while (true) { ready = 1; MPI_Send(&ready, 1, MPI_INT, 0, 0, MPI_COMM_WORLD); MPI_Recv(&waittime, 1, MPI_INT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &status); // 用-1作为终止标记,收到后退出循环 if (waittime == -1) break; task(waittime, worldrank); } }
修改后的管理节点代码
if (worldrank == 0) { for (int k = 0; k < nwaits; k++) { MPI_Recv(&ready, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); MPI_Send(&waittimes[k], 1, MPI_INT, status.MPI_SOURCE, 0, MPI_COMM_WORLD); } // 给所有工作节点发送终止信号 int terminate = -1; for (int i = 1; i < worldsize; i++) { MPI_Recv(&ready, 1, MPI_INT, i, MPI_ANY_TAG, MPI_COMM_WORLD, &status); MPI_Send(&terminate, 1, MPI_INT, i, 0, MPI_COMM_WORLD); } }
额外注意事项
- 输出乱序问题:多进程直接用
cout打印会导致输出混乱,建议工作节点把输出内容发送给管理节点,由管理节点统一打印。 - Sleep参数单位:Windows的
Sleep参数是毫秒,代码中Sleep(waittime)实际只等待了waittime毫秒,若要等待秒数,需改成Sleep(waittime * 1000)。
内容的提问来源于stack exchange,提问作者storluffarn
相关产品推荐
相关产品推荐

