MPI中的MPI_Allgather和MPI_Alltoall功能之间的主要区别是什么?
我的意思是,有人可以给我一些例子,其中MPI_Allgather会有所帮助,MPI_Alltoall会不会这样做?反之亦然。
我无法理解主要区别?看起来在这两种情况下,所有进程都会将send_cnt元素发送给参与通信器的每个其他进程并接收它们?
谢谢
答案 0 :(得分:64)
一张图片说的超过千字,所以这里有几张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
- 每个进程中的发送缓冲区都像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...
的{{1}}必须等于recvcnt
。
很明显,对于相同大小的接收数据,每个进程发送的数据量是不同的。为了使两个操作相等,一个必要条件是在两种情况下发送的缓冲区的大小相等,即sendcnt
,这仅在n_procs * sendcnt == sendcnt
时才可能,即如果只有一个进程,或n_procs == 1
,即根本没有数据发送。因此,在两种操作都可以互换的情况下,没有实际可行的情况。但是,可以通过重复sendcnt == 0
次发送缓冲区中的相同数据来模拟MPI_Allgather
MPI_Alltoall
(如Tyler Gill所述)。以下是n_procs
对单元素发送缓冲区的操作:
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
的行为。
答案 1 :(得分:11)
这两个截图有一个快速解释:
MPI_Allgatherv
MPI_Alltoallv
虽然这是MPI_Allgatherv和MPI_Alltoallv之间的比较,但它也解释了MPI_Allgather与MPI_Alltoall的不同之处。
答案 2 :(得分:4)
虽然这两种方法确实非常相似,但两者之间似乎存在一个至关重要的区别。
MPI_Allgather以每个进程在其接收缓冲区中具有完全相同的数据结束,每个进程为整个数组提供单个值。例如,如果一组进程中的每一个都需要与其他人共享关于其状态的单个值,则每个进程将提供其单个值。然后将这些值发送给每个人,因此每个人都会拥有相同结构的副本。
MPI_Alltoall不会向其他进程发送相同的值。每个进程都指定一个值给予彼此进程,而不是提供应与其他进程共享的单个值。换句话说,对于n个进程,每个进程必须指定要共享的n个值。然后,对于每个处理器j,其第k个值将被发送到接收缓冲器中的处理k的第j个索引。如果每个进程对于每个其他进程都有一条唯一的唯一消息,那么这很有用。
作为最后一点,在每个进程用相同的值填充其发送缓冲区的情况下,运行allgather和alltoall的结果将是相同的。唯一的区别是allgather可能会更有效率。