用MPI在后台听和回复

时间:2015-11-21 22:41:24

标签: c parallel-processing mpi

我想实现一个流程有一些工作的场景,系统中的所有其他流程都会向此流程发出请求。当然,这些其他进程不知道哪个进程有工作,所以他们必须向其他每个进程发送消息并检查他们是否有工作。如果该过程没有工作,他们将回复-1。当进程从有捐赠作业的进程获得回复时,它将从中获取作业并忙于执行作业。但是如果它从任何其他进程获得请求它很忙,它将以-1回复。我无法让这个工作。到目前为止,我已经在下面实现了MPI_Send和MPI_Recv的解决方案:

 /* Master process has all the jobs to donate */
if(rank == MasterProcess)
   while(haveJobToDonate){
       /* listen to requests with MPI_ANY_SOURCE,MPI_ANY_TAG */
       MPI_Recv()
        /* when request received send a job to requesting process */
       MPI_Send()
   }
   /* if no job, then finish */

}else if(rank != MasterProcess){
     /* find a job */
     findJob()

}

findJob()方法如下:

findJob(){
   /*set target to 0 */
   while(JobNotFound){
      MPI_Send(target)
      MPI_Recv(fromTarget)
      /* if no job returned */
      if(req == -1)
         target += (target%NumberOfProcesses)
      else
         return req

   }

}

但是你可以猜到问题是如果进程没有作业,它就不会回复请求进程,并且该进程将阻塞并等待。另一个问题是,如果一个进程得到了一个工作,它将完成它的工作,它将不会收听请求。如果进程发送了请求,那么它将阻塞并等待。这将使程序阻止。 MPI中是否有任何可以帮助解决此问题的功能?

1 个答案:

答案 0 :(得分:0)

你问题的某些限制,例如问题中的解释,对我来说有点过于模糊,无法在答案中完全具体。例如,由于主进程是首先分配工作的进程,为什么即使在分发了所有工作之后它也不继续进行簿记,至少指示哪个进程拥有什么?这样,至少你的自由工作者想要更多的工作知道要偷哪个工人。

更好的是,我想你的工作最初由主人按批次分发(否则,一旦主人完成分发,任何自由工人都知道没有什么可做的)。因此,您可以查看the various schedule policies of OpenMP,了解如何更改批次以管理整体负载平衡。这个问题在OpenMP中是一个非常常见的问题,它已经在那里得到了解决,例如schedule(guided)。这是一种解决方案,您可以在主进程中轻松地重新实现,这可以避免任何类型的工作者与工作者之间的通信,因此比工作窃取更简单。

现在,假设工作窃取确实是您想要/需要做的,可能的解决方案是使用一些片面通信。每个工作人员都会在暴露给世界的内存窗口中预订它拥有的任务列表。然后,每当一个进程想要从中窃取一些工作时,它会用MPI_Win_lock()锁定此窗口,然后用MPI_Compare_and_swap()窃取原子任务,最后释放带有MPI_Win_unlock()的窗口。 MPI_Compare_and_swap()的使用方式将对应于将探测到的远程工作者列表中的任务索引与当前进程想要窃取的任务进行比较。如果两者都匹配,那么这意味着该任务可以被盗,并且当前进程窃取它并通过已经完成的任何方式替换它,或者,例如,减去其等级以指示任何其他进程即将到来后来它现在拥有它...行动的原子方面是非常重要,因为另一个工人可以尝试在同一时间做同样的事情。如果没有原子探测和更新操作,来自不同进程的探测和更新操作可能会相互交错,从而导致错误的解决方案。

在此阶段,根据当前工作人员刚刚获得的新任务是否可以窃取某些工作,它必须原子用{{更新>自己的任务列表共享窗口1}} + MPI_Win_lock() + MPI_Win_{put,accumulate,fetch_and_op}()一组来电。然后,它可以继续开始实际处理其新获得的任务。

有关如何以原子方式使用这些单面调用的简单示例,您可以查看this answer

注意,这只能从MPI 3.0开始。