我有一个在Windows HPC群集(12个节点,每个节点24个核心)上运行的C ++ MPI程序。
有一个问题。每个任务的执行时间可能截然不同,因此我无法提前告知。平均分配任务将导致许多进程处于空闲状态。这会浪费大量计算机资源,并使总执行时间更长。
我正在考虑一种可行的解决方案。
据我了解,此方案需要跨节点/进程的通用计数器(以避免不同的MPI进程执行同一宗地),并且对其进行更改需要一些锁定/同步机制。它当然有开销,但是通过适当的调整,我认为它可以帮助提高性能。
我对MPI不太熟悉,并且有一些实现问题。我可以想到两种方法来实现此通用计数器
不幸的是,我对这两种技术都不熟悉,并且想探究上述两种方法的可能性,实现或可能的缺点。样例代码将不胜感激。
如果您还有其他解决问题或建议的方法,那也很好。谢谢。
后续行动:
感谢所有有用的建议。我按照使用进程0作为任务分发者的方案实施了一个测试程序。
#include <iostream>
#include <mpi.h>
using namespace std;
void doTask(int rank, int i){
cout<<rank<<" got task "<<i<<endl;
}
int main ()
{
int numTasks = 5000;
int parcelSize = 100;
int numParcels = (numTasks/parcelSize) + (numTasks%parcelSize==0?0:1);
//cout<<numParcels<<endl;
MPI_Init(NULL, NULL);
int rank, nproc;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
MPI_Status status;
MPI_Request request;
int ready = 0;
int i = 0;
int maxParcelNow = 0;
if(rank == 0){
for(i = 0; i <numParcels; i++){
MPI_Recv(&ready, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
//cout<<i<<"Yes"<<endl;
MPI_Send(&i, 1, MPI_INT, status.MPI_SOURCE, 0, MPI_COMM_WORLD);
//cout<<i<<"No"<<endl;
}
maxParcelNow = i;
cout<<maxParcelNow<<" "<<numParcels<<endl;
}else{
int counter = 0;
while(true){
if(maxParcelNow == numParcels) {
cout<<"Yes exiting"<<endl;
break;
}
//if(maxParcelNow == numParcels - 1) break;
ready = 1;
MPI_Send(&ready, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
//cout<<rank<<"send"<<endl;
MPI_Recv(&i, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
//cout<<rank<<"recv"<<endl;
doTask(rank, i);
}
}
MPI_Bcast(&maxParcelNow, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Finalize();
return 0;
}
它不起作用,并且永不停止。关于如何使其工作的任何建议?这段代码是否反映了这个想法,还是我错过了什么?谢谢
答案 0 :(得分:1)
[将我的评论转换为答案...]
给定n
进程,您可以让您的第一个进程p0
为其他n - 1
进程分派任务。首先,它将与其他n - 1
进程进行点对点通信,以便每个人都有工作要做,然后它将阻塞在Recv
上。当任何给定过程完成时,例如说p3
,它将把结果发送回p0
。此时,p0
将通过以下两种方式之一向p3
发送另一条消息:
1)另一个任务
或
2)如果没有剩余任务,则发出某种终止信号。 (使用消息的“标签”是一种简单的方法。)
很显然,p0
会循环遍历该逻辑,直到没有剩下的任务为止,在这种情况下,它也会调用MPI_Finalize
。
与您在评论中的想法不同,这不是轮循。它首先将工作分配给每个流程或工人,然后每完成一个工作就给另一工作...