据我所知,这是主节点 while 循环中的 recv 的结果。
...
while (1) {
// Receive results from slave.
stat = world.recv(MPI_ANY_SOURCE,MPI_ANY_TAG);
...
当有来自一个从属节点的消息时,主节点无法获取任何消息,直到 while 循环内的代码完成(这需要一些时间,因为存在睡眠),因为主节点没有并行运行。因此,在第一个从站完成发送消息之前,所有其他从站都无法开始发送消息。然后下一个从站可以开始发送消息,但是所有其他从站都将停止,直到执行 while 循环内的代码。
这会导致您看到的行为,即从站通信非常缓慢。为避免此问题,您需要实现点对点通信非阻塞或使用全局通信。
更新 1:
让我们假设主人分发了他的数据。现在他等着奴隶们回来报告。当第一个奴隶报告回来时,他将首先发送他的 REPORTTAG,然后是他的 DONETAG。现在主人会给他送回一份新工作,如果
currentTask < numtasks
现在奴隶们重新开始计算。现在的情况可能是,在他完成之前,主人只能处理另一个奴隶。因此,一开始的奴隶现在再次先发送他的 REPORTTAG,然后发送他的 DONETAG,然后得到一份新工作。当这种情况持续到最后时,只有 2 个奴隶得到了新的工作,其余的都无法完成他们的工作。所以在某些时候这是真的:
currentTask >= numtasks
现在你停止了所有的工作,即使不是所有的奴隶都报告了他们的数据并且已经完成了不止一项任务。
当不同节点的网络连接差异很大时,最容易出现此问题。原因是发送和接收在调用后没有被处理,相反,如果其中两个函数能够进行某种握手,则通信发生。
作为解决方案,我建议:
- 在杀死所有作业之前确保所有奴隶都完成
- 使用收集和分散而不是消息,然后在每个任务之后同步所有从属。
- 如果消息不大,请使用缓冲或无缓冲的发送和接收操作。确保您没有在 Master 上出现内存溢出
- 从主/从更改为更并行的工作模式,例如将所有任务划分到两个节点,然后将任务从这些节点进一步划分到接下来的两个,依此类推。最后以这种方式将任务发送回去。该解决方案可能还具有通信成本仅为 O(logn) 而不是 O(n) 的优点。
希望这有帮助。