【问题标题】:Difference between MPI_Allgather and MPI_Alltoall functions?MPI_Allgather 和 MPI_Alltoall 函数之间的区别?
【发布时间】:2013-02-09 13:07:57
【问题描述】:

MPI 中的 MPI_Allgather 和 MPI_Alltoall 函数之间的主要区别是什么?

我的意思是有人可以给我一些例子,说明 MPI_Allgather 会有所帮助而 MPI_Alltoall 不会?反之亦然。

我无法理解主要区别?看起来在这两种情况下,所有进程都将 send_cnt 元素发送到参与通信器的每个其他进程并接收它们?

谢谢

【问题讨论】:

  • TL;DR “所有聚集”就像聚集+广播(或者每个人都聚集)。 “All to all”就像转置一个矩阵。

标签: mpi


【解决方案1】:

一张图说千言万语,这里有几张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_ScatterMPI_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 数据类型987654331@,那么recvcnt必须等于sendcnt

很明显,对于相同大小的接收数据,每个进程发送的数据量是不同的。两个操作要相等,一个必要条件是两种情况下发送的缓冲区大小相等,即n_procs * sendcnt == sendcnt,只有n_procs == 1才有可能,即只有一个进程,或者@ 987654336@,即根本没有发送数据。因此,实际上不存在两种操作真正可互换的情况。但是可以通过在发送缓冲区中重复n_procs 次相同的数据来模拟MPI_AllgatherMPI_Alltoall(正如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_Allgather模拟MPI_Alltoall的动作。

【讨论】:

    【解决方案2】:

    这两张截图有一个简单的解释:

    MPI_Allgatherv

    MPI_Alltoallv

    虽然这是 MPI_Allgatherv 和 MPI_Alltoallv 之间的比较,但它也解释了 MPI_Allgather 与 MPI_Alltoall 的不同之处。

    【讨论】:

      【解决方案3】:

      虽然这两种方法确实非常相似,但两者之间似乎存在一个关键区别。

      MPI_Allgather 以每个进程在其接收缓冲区中具有完全相同的数据结束,并且每个进程为整个数组贡献一个值。例如,如果一组进程中的每一个都需要与其他人共享有关其状态的某个单一值,则每个进程都将提供它们的单一值。然后这些值将发送给每个人,因此每个人都会拥有相同结构的副本。

      MPI_Alltoall 不会向其他进程发送相同的值。每个进程不提供应该与其他进程共享的单个值,而是指定一个值给其他进程。换句话说,对于 n 个进程,每个进程都必须指定 n 个要共享的值。然后,对于每个处理器 j,它的第 k 个值将被发送到处理 k 在接收缓冲区中的第 j 个索引。如果每个进程对每个其他进程都有一条唯一的消息,这将很有用。

      最后一点,运行 allgather 和 alltoall 的结果在每个进程用相同的值填充其发送缓冲区的情况下是相同的。唯一的区别是 allgather 可能会更有效率。

      【讨论】:

        猜你喜欢
        • 2011-08-17
        • 1970-01-01
        • 1970-01-01
        • 2014-06-08
        • 2020-03-25
        • 2017-07-12
        • 1970-01-01
        • 1970-01-01
        • 2013-02-14
        相关资源
        最近更新 更多