大量处理器的 MPI 发送和接收模式

MPI Send and Receive modes for large number of processors

我知道有很多关于 MPI 发送和接收的不同模式的问题和答案,但我相信我的不同,或者我根本无法将这些答案应用于我的问题。

反正我的场景是这样的。该代码适用于可能具有数千个核心的高性能集群,这些集群被组织成一个多维网格。在我的算法中,有两个连续的操作需要执行,我们称它们为 AB,其中 A B 之前。简要说明如下:

A:每个处理器都有多个缓冲区。它必须将这些缓冲区中的每一个发送到一组特定的处理器。对于每个要发送的缓冲区,接收处理器的集合可能不同。发送是操作的最后一步A.

B:每个处理器从一组处理器接收一组缓冲区。操作 B 将在接收到 all 缓冲区后处理这些缓冲区。该操作的结果将存储在固定位置(既不在发送缓冲区也不在接收缓冲区中)

还给出了以下属性:

要发送和接收,AB 都必须自己使用(嵌套)循环来发送和接收不同的缓冲器。但是,我们不能对这些发送和接收语句的顺序做出任何假设,即对于任何两个缓冲区 buf0buf1 我们 不能 保证如果 buf0buf1 之前被某个处理器接收,buf0 也在 buf1 之前发送。请注意,由于确定 receiving/sending 处理器集的复杂性,目前尚不能使用 MPI_Broadcast 等组操作。

问题:我应该使用哪种发送和接收模式?我已经阅读了很多关于这些不同模式的不同内容,但我无法真正了解它们。最重要的 属性 是无死锁,其次是性能。我倾向于在 A 中使用 MPI_Isend() 而不检查请求状态,并再次在 B[=68= 中使用非阻塞 MPI_IRecv() ] 的循环,然后使用 MPI_Waitall() 确保接收到所有缓冲区(因此,所有缓冲区也已发送并且处理器已同步)。

这是正确的方法吗,还是我必须使用缓冲发送或完全不同的方法?我在 MPI 方面没有太多经验,文档也没有太大帮助。

根据您描述问题的方式,我认为 MPI_Isend 可能是 A 的最佳(唯一?)选项,因为它保证无阻塞,而MPI_Send 可能 是非阻塞的,但前提是它能够在内部缓冲您的发送缓冲区。

然后您应该能够使用 MPI_Barrier 以便所有进程同时进入 B。但这可能会影响性能。如果您不坚持让所有进程同时进入 B,有些进程可以更快地开始接收消息。此外,考虑到您不相交的发送和接收缓冲区,这应该是安全的。

对于B,可以使用MPI_IrecvMPI_RecvMPI_Irecv 可能会更快,因为标准 MPI_Recv 可能正在等待来自另一个进程的较慢发送。

无论是否在receiving端阻塞,都应该在循环结束前调用MPI_Waitall以确保所有send/recv操作都成功完成.

另外一点:您可以利用 MPI_ANY_SOURCEMPI_Recv 以阻塞方式接收消息并立即对其进行操作,无论它们到达的顺序如何。但是,鉴于您指定在收到 所有 数据之前不会对数据进行任何操作,这可能没有那么有用。

最后:如 these recommendations 中所述,如果您可以重组代码以便仅使用 MPI_SSend,您将获得最佳性能。在这种情况下,您完全可以避免任何缓冲。为此,您必须让所有进程首先调用 MPI_Irecv,然后 开始通过 MPI_Ssend 发送。以这种方式进行重构可能没有您想的那么难,特别是如果像您所说的那样,每个进程都可以独立计算出将从谁那里接收到哪些消息。