4.8 全局到全局的分散/收集(ALL-to-ALL Scatter/Gather) BACKWARDFORWARD


MPI_ALLTOALL(sendbuf, sendcount, sendtype, recvbuf, recvcount,
             recvtype, comm)
 IN  sendbuf     发送消息缓冲区的起始地址(可变)
 IN  sendcount   发送到每个进程的数据个数(整型)
 IN  sendtype    发送消息缓冲区中的数据类型(句柄)
 OUT recvbuf     接收消息缓冲区的起始地址(可变)
 IN  recvcount   从每个进程中接收的元素个数(整型)
 IN  recvtype    接收消息缓冲区的数据类型(句柄)
 IN  comm        通信子(句柄)

int MPI_Alltoall(void* sendbuf, int sendcount, MPI_Datatype sendtype,
                 void* recvbuf, int recvcount, MPI_Datatype recvtype,
                 MPI_Comm comm)
MPI_ALLTOALL(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT,
             RECVTYPE, COMM, IERROR)
    <type> SENDBUF(*), RECVBUF(*)
    INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, COMM, IERROR

MPI_ALLTOALL是对MPI_ALLGATHER的扩展,区别是每个进程可以向每个接收者发送数目不同的数据.第i个进程发送的第j块数据将被第j 个进程接收并存放在其接收消息缓冲区recvbuf的第i块.

每个进程的sendcount和sendtype的类型必须和所有其他进程的recvcount和recvtype相同,这就意谓着在每个进程和根进程之间,发送的数据量必须和接收的数据量相等.但发送方和接收方之间的不同数据类型映射仍然是允许的.

调用MPI_ALLTOALL相当于每个进程对每个进程(包括它自身)执行了一次调用:

    MPI_Send(sendbuf+i*sendcount*extent(sendtype),sendcount,
             sendtype,i,...),

然后再执行一次从所有其他进程接收数据的调用:

    MPI_Recv(recvbuf+i*recvcount*extent(recvtype),recvcount,i,...).

所有参数对每个进程都是很重要的,而且所有进程中的comm值必须一致.

MPI_ALLTOALLV(sendbuf, sendcounts, sdispls, sendtype, recvbuf,
              recvcounts, rdispls, recvtype, comm)
 IN  sendbuf     发送消息缓冲区的起始地址(可变)
 IN  sendcounts  长度为组大小的整型数组, 存放着发送给每个进程的数据
                 个数
 IN  sdispls     长度为组大小的整型数组,每个入口j存放着相对于sendbuf
                 的位移,此位移处存放着输出到进程j的数据
 IN  sendtype    发送消息缓冲区中的数据类型(句柄)
 OUT recvbuf     接收消息缓冲区的起始地址(可变)
 IN  recvcounts  长度为组大小的整型数组, 存放着从每个进程中接收的元
                 素个数(整型)
 IN  rdispls     长度为组大小的整型数组,每个入口i存放着相对于recvbuf
                 的位移,此位移处存放着从进程i接收的数据
 IN  recvtype    接收消息缓冲区的数据类型(句柄)
 IN  comm        通信子(句柄)

int MPI_Alltoallv(void* sendbuf, int *sendcounts, int *sdispls,
                  MPI_Datatype sendtype, void* recvbuf,
                  int *recvcounts, int *rdispls,
                  MPI_Datatype recvtype, MPI_Comm comm)
MPI_ALLTOALLV(SENDBUF, SENDCOUNTS, SDISPLS, SENDTYPE, RECVBUF,
              RECVCOUNTS, RDISPLS, RECVTYPE, COMM, IERROR)
    <type>  SENDBUF(*), RECVBUF(*)
    INTEGER SENDCOUNTS(*), SDISPLS(*), SENDTYPE, RECVCOUNTS(*),
            RDISPLS(*), RECVTYPE, COMM, IERROR

MPI_ALLTOALLV在MPI_ALLTOALL的基础上进一步增加了灵活性,它可以由sdispls指定待发送数据的位置,在接收方则由rdispls 指定接收的数据存放在缓冲区的偏移量.

第i个进程所发送的第j块由第j个进程接收并存放到其接收消息缓冲区recvbuf 的第i块中,这些块的大小可以不一样.

进程i中sendcount[j]和sendtype的类型必须和进程j中recvcount[i]和recvtype相同,这就意谓着在一对进程间,发送的数据量必须和接收的数据量相等.但发送方和接收方之间的不同数据类型映射仍然是允许的.

调用MPI_ALLTOALLV相当于每个进程对其他进程发了一条消息:

    MPI_Send(sendbuf+displs[i]*extent(sendtype),sendcounts[i],
             sendtype,i,...),

其他进程执行下列调用来接收一条消息:

    MPI_Recv(recvbuf+displs[i]*extent(recvtype),recvcounts[i],
             recvtype,i,...).

所有参数对每个进程都是很重要的,并且所有进程中的comm值必须一致.

原则: MPI_ALLTOALL和MPI_ALLTOALLV为用户提供了更大的灵活性,它可以实现n 次独立的点对点通信,但里作了两处限制:1)所有数据必须是同一类型;2)所有的消息必须按顺序进行分散和收集操作(原则结尾)

对实现者的建议: 尽管上面在点对点操作的基础上讨论的集合通信隐含了从发送者到接收者的直接通信,但有时为了获得更高的效率,实现者可以采用树状模式,即消息可以由中间节点分成两部分,分散时为分离操作,收集时为合并操作(对实现者的建议结尾)


Copyright: NPACT BACKWARDFORWARD