大量处理器的 MPI 发送和接收模式
MPI Send and Receive modes for large number of processors
我知道有很多关于 MPI 发送和接收的不同模式的问题和答案,但我相信我的不同,或者我根本无法将这些答案应用于我的问题。
反正我的场景是这样的。该代码适用于可能具有数千个核心的高性能集群,这些集群被组织成一个多维网格。在我的算法中,有两个连续的操作需要执行,我们称它们为 A 和 B,其中 A 在 B 之前。简要说明如下:
A:每个处理器都有多个缓冲区。它必须将这些缓冲区中的每一个发送到一组特定的处理器。对于每个要发送的缓冲区,接收处理器的集合可能不同。发送是操作的最后一步A.
B:每个处理器从一组处理器接收一组缓冲区。操作 B 将在接收到 all 缓冲区后处理这些缓冲区。该操作的结果将存储在固定位置(既不在发送缓冲区也不在接收缓冲区中)
还给出了以下属性:
- 在A中,每个处理器都可以计算发送给哪些处理器,如果一个处理器从同一个发送处理器接收到多个缓冲区,它还可以计算相应的标签(这很有可能)。
- 在 B 中,每个处理器还可以计算它将从哪些处理器接收信息,以及发送消息时使用的相应标签。
- 每个处理器都有自己的发送缓冲区和接收缓冲区,并且它们是不相交的(即没有处理器将其发送缓冲区也用作接收缓冲区,反之亦然)。
- A 和 B 在 A 之前和之后的其他操作中循环执行B。我们可以确保在下一次循环迭代之前不会再次使用发送缓冲区,其中在 A 中填充新数据,并且接收缓冲区也不会再次使用直到下一次迭代,它们用于在操作 B.
中接收新数据
- A 和 B 之间的过渡,如果可能的话,应该是一个同步点,即我们要确保所有处理器进入B同时
要发送和接收,A 和 B 都必须自己使用(嵌套)循环来发送和接收不同的缓冲器。但是,我们不能对这些发送和接收语句的顺序做出任何假设,即对于任何两个缓冲区 buf0
和 buf1
我们 不能 保证如果 buf0
在 buf1
之前被某个处理器接收,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_Irecv
或MPI_Recv
。 MPI_Irecv
可能会更快,因为标准 MPI_Recv
可能正在等待来自另一个进程的较慢发送。
无论是否在receiving端阻塞,都应该在循环结束前调用MPI_Waitall
以确保所有send/recv操作都成功完成.
另外一点:您可以利用 MPI_ANY_SOURCE
和 MPI_Recv
以阻塞方式接收消息并立即对其进行操作,无论它们到达的顺序如何。但是,鉴于您指定在收到 所有 数据之前不会对数据进行任何操作,这可能没有那么有用。
最后:如 these recommendations 中所述,如果您可以重组代码以便仅使用 MPI_SSend
,您将获得最佳性能。在这种情况下,您完全可以避免任何缓冲。为此,您必须让所有进程首先调用 MPI_Irecv
、,然后 开始通过 MPI_Ssend
发送。以这种方式进行重构可能没有您想的那么难,特别是如果像您所说的那样,每个进程都可以独立计算出将从谁那里接收到哪些消息。
我知道有很多关于 MPI 发送和接收的不同模式的问题和答案,但我相信我的不同,或者我根本无法将这些答案应用于我的问题。
反正我的场景是这样的。该代码适用于可能具有数千个核心的高性能集群,这些集群被组织成一个多维网格。在我的算法中,有两个连续的操作需要执行,我们称它们为 A 和 B,其中 A 在 B 之前。简要说明如下:
A:每个处理器都有多个缓冲区。它必须将这些缓冲区中的每一个发送到一组特定的处理器。对于每个要发送的缓冲区,接收处理器的集合可能不同。发送是操作的最后一步A.
B:每个处理器从一组处理器接收一组缓冲区。操作 B 将在接收到 all 缓冲区后处理这些缓冲区。该操作的结果将存储在固定位置(既不在发送缓冲区也不在接收缓冲区中)
还给出了以下属性:
- 在A中,每个处理器都可以计算发送给哪些处理器,如果一个处理器从同一个发送处理器接收到多个缓冲区,它还可以计算相应的标签(这很有可能)。
- 在 B 中,每个处理器还可以计算它将从哪些处理器接收信息,以及发送消息时使用的相应标签。
- 每个处理器都有自己的发送缓冲区和接收缓冲区,并且它们是不相交的(即没有处理器将其发送缓冲区也用作接收缓冲区,反之亦然)。
- A 和 B 在 A 之前和之后的其他操作中循环执行B。我们可以确保在下一次循环迭代之前不会再次使用发送缓冲区,其中在 A 中填充新数据,并且接收缓冲区也不会再次使用直到下一次迭代,它们用于在操作 B. 中接收新数据
- A 和 B 之间的过渡,如果可能的话,应该是一个同步点,即我们要确保所有处理器进入B同时
要发送和接收,A 和 B 都必须自己使用(嵌套)循环来发送和接收不同的缓冲器。但是,我们不能对这些发送和接收语句的顺序做出任何假设,即对于任何两个缓冲区 buf0
和 buf1
我们 不能 保证如果 buf0
在 buf1
之前被某个处理器接收,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_Irecv
或MPI_Recv
。 MPI_Irecv
可能会更快,因为标准 MPI_Recv
可能正在等待来自另一个进程的较慢发送。
无论是否在receiving端阻塞,都应该在循环结束前调用MPI_Waitall
以确保所有send/recv操作都成功完成.
另外一点:您可以利用 MPI_ANY_SOURCE
和 MPI_Recv
以阻塞方式接收消息并立即对其进行操作,无论它们到达的顺序如何。但是,鉴于您指定在收到 所有 数据之前不会对数据进行任何操作,这可能没有那么有用。
最后:如 these recommendations 中所述,如果您可以重组代码以便仅使用 MPI_SSend
,您将获得最佳性能。在这种情况下,您完全可以避免任何缓冲。为此,您必须让所有进程首先调用 MPI_Irecv
、,然后 开始通过 MPI_Ssend
发送。以这种方式进行重构可能没有您想的那么难,特别是如果像您所说的那样,每个进程都可以独立计算出将从谁那里接收到哪些消息。