MPI 中的 MPI_Allgather 和 MPI_Alltoall 函数之间的主要区别是什么?
我的意思是有人可以给我一些例子,说明 MPI_Allgather 会有所帮助而 MPI_Alltoall 不会?反之亦然。
我无法理解主要区别?看起来在这两种情况下,所有进程都将 send_cnt 元素发送到参与通信器的每个其他进程并接收它们?
谢谢你
MPI 中的 MPI_Allgather 和 MPI_Alltoall 函数之间的主要区别是什么?
我的意思是有人可以给我一些例子,说明 MPI_Allgather 会有所帮助而 MPI_Alltoall 不会?反之亦然。
我无法理解主要区别?看起来在这两种情况下,所有进程都将 send_cnt 元素发送到参与通信器的每个其他进程并接收它们?
谢谢你
一张图说千言万语,所以这里有几张ASCII艺术图:
rank send buf recv buf
---- -------- --------
0 a,b,c MPI_Allgather a,b,c,A,B,C,#,@,%
1 A,B,C ----------------> a,b,c,A,B,C,#,@,%
2 #,@,% a,b,c,A,B,C,#,@,%
这只是常规的MPI_Gather
,只有在这种情况下所有进程都接收数据块,即操作是无根的。
rank send buf recv buf
---- -------- --------
0 a,b,c MPI_Alltoall a,A,#
1 A,B,C ----------------> b,B,@
2 #,@,% c,C,%
(a more elaborate case with two elements per process)
rank send buf recv buf
---- -------- --------
0 a,b,c,d,e,f MPI_Alltoall a,b,A,B,#,@
1 A,B,C,D,E,F ----------------> c,d,C,D,%,$
2 #,@,%,$,&,* e,f,E,F,&,*
(如果每个元素都按发送它的等级着色,看起来会更好,但是......)
MPI_Alltoall
作为组合工作MPI_Scatter
-MPI_Gather
每个进程中的发送缓冲区像 in 一样拆分MPI_Scatter
,然后每一列块由各自的进程收集,其等级与块列的编号匹配。MPI_Alltoall
也可以看作是全局转置操作,作用于数据块。
是否存在两种操作可以互换的情况?要正确回答这个问题,必须简单地分析发送缓冲区中数据的大小和接收缓冲区中数据的大小:
operation send buf size recv buf size
--------- ------------- -------------
MPI_Allgather sendcnt n_procs * sendcnt
MPI_Alltoall n_procs * sendcnt n_procs * sendcnt
接收缓冲区大小实际上是n_procs * recvcnt
,但是 MPI 要求发送的基本元素的数量应该等于接收的基本元素的数量,因此如果在发送和接收部分使用相同的 MPI 数据类型MPI_All...
,则recvcnt
必须等于sendcnt
。
很明显,对于相同大小的接收数据,每个进程发送的数据量是不同的。为了使这两个操作相等,一个必要条件是两种情况下发送的缓冲区的大小相等,即n_procs * sendcnt == sendcnt
,只有当 时才有可能n_procs == 1
,即只有一个进程,或者如果sendcnt == 0
,即没有数据正在发送一点也不。因此,实际上不存在两种操作真正可互换的情况。但是可以通过在发送缓冲区中重复多次相同的数据来模拟MPI_Allgather
(MPI_Alltoall
正如n_procs
Tyler Gill 已经指出的那样)。这是MPI_Allgather
使用单元素发送缓冲区的操作:
rank send buf recv buf
---- -------- --------
0 a MPI_Allgather a,A,#
1 A ----------------> a,A,#
2 # a,A,#
在这里同样实现MPI_Alltoall
:
rank send buf recv buf
---- -------- --------
0 a,a,a MPI_Alltoall a,A,#
1 A,A,A ----------------> a,A,#
2 #,#,# a,A,#
反过来是不可能的——在一般情况下无法模拟MPI_Alltoall
with的动作。MPI_Allgather
虽然这两种方法确实非常相似,但两者之间似乎存在一个关键区别。
MPI_Allgather 以每个进程在其接收缓冲区中具有完全相同的数据结束,并且每个进程为整个数组贡献一个值。例如,如果一组进程中的每一个都需要与其他人共享有关其状态的某个单一值,则每个进程都将提供它们的单一值。然后将这些值发送给每个人,因此每个人都会拥有相同结构的副本。
MPI_Alltoall 不会向其他进程发送相同的值。每个进程不提供应该与其他进程共享的单个值,而是指定一个值给其他进程。换句话说,对于 n 个进程,每个进程都必须指定 n 个值来共享。然后,对于每个处理器 j,它的第 k 个值将被发送到处理 k 在接收缓冲区中的第 j 个索引。如果每个进程对每个其他进程都有一条唯一的消息,这将很有用。
最后一点,运行 allgather 和 alltoall 的结果在每个进程用相同的值填充其发送缓冲区的情况下是相同的。唯一的区别是 allgather 可能会更有效率。