17.2.311. MPI_Scatter

MPI_Scatter, MPI_Iscatter, MPI_Scatter_init - 将数据从一个任务发送给组内的所有任务。

17.2.311.1. 语法

17.2.311.1.1. C语法

#include <mpi.h>

int MPI_Scatter(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
     void *recvbuf, int recvcount, MPI_Datatype recvtype, int root,
     MPI_Comm comm)

int MPI_Iscatter(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
     void *recvbuf, int recvcount, MPI_Datatype recvtype, int root,
     MPI_Comm comm, MPI_Request *request)

int MPI_Scatter_init(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
     void *recvbuf, int recvcount, MPI_Datatype recvtype, int root,
     MPI_Comm comm, MPI_Info info, MPI_Request *request)

17.2.311.1.2. Fortran语法

USE MPI
! or the older form: INCLUDE 'mpif.h'
MPI_SCATTER(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT,
             RECVTYPE, ROOT, COMM, IERROR)
     <type>  SENDBUF(*), RECVBUF(*)
     INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, ROOT
     INTEGER COMM, IERROR

MPI_ISCATTER(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT,
             RECVTYPE, ROOT, COMM, REQUEST, IERROR)
     <type>  SENDBUF(*), RECVBUF(*)
     INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, ROOT
     INTEGER COMM, REQUEST, IERROR

MPI_SCATTER_INIT(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT,
             RECVTYPE, ROOT, COMM, INFO, REQUEST, IERROR)
     <type>  SENDBUF(*), RECVBUF(*)
     INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, ROOT
     INTEGER COMM, INFO, REQUEST, IERROR

17.2.311.1.3. Fortran 2008 语法

USE mpi_f08
MPI_Scatter(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype,
             root, comm, ierror)
     TYPE(*), DIMENSION(..), INTENT(IN) :: sendbuf
     TYPE(*), DIMENSION(..) :: recvbuf
     INTEGER, INTENT(IN) :: sendcount, recvcount, root
     TYPE(MPI_Datatype), INTENT(IN) :: sendtype, recvtype
     TYPE(MPI_Comm), INTENT(IN) :: comm
     INTEGER, OPTIONAL, INTENT(OUT) :: ierror

MPI_Iscatter(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype,
             root, comm, request, ierror)
     TYPE(*), DIMENSION(..), INTENT(IN), ASYNCHRONOUS :: sendbuf
     TYPE(*), DIMENSION(..), ASYNCHRONOUS :: recvbuf
     INTEGER, INTENT(IN) :: sendcount, recvcount, root
     TYPE(MPI_Datatype), INTENT(IN) :: sendtype, recvtype
     TYPE(MPI_Comm), INTENT(IN) :: comm
     TYPE(MPI_Request), INTENT(OUT) :: request
     INTEGER, OPTIONAL, INTENT(OUT) :: ierror

MPI_Scatter_init(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype,
             root, comm, info, request, ierror)
     TYPE(*), DIMENSION(..), INTENT(IN), ASYNCHRONOUS :: sendbuf
     TYPE(*), DIMENSION(..), ASYNCHRONOUS :: recvbuf
     INTEGER, INTENT(IN) :: sendcount, recvcount, root
     TYPE(MPI_Datatype), INTENT(IN) :: sendtype, recvtype
     TYPE(MPI_Comm), INTENT(IN) :: comm
     TYPE(MPI_Info), INTENT(IN) :: info
     TYPE(MPI_Request), INTENT(OUT) :: request
     INTEGER, OPTIONAL, INTENT(OUT) :: ierror

17.2.311.2. 输入参数

  • sendbuf: 发送缓冲区的地址(仅在根节点有效,可选)。

  • sendcount: 发送给每个进程的元素数量(整数,仅在根节点有效)。

  • sendtype: 发送缓冲区元素的数据类型(句柄,仅在根节点有效)。

  • recvcount: 接收缓冲区中的元素数量(整数)。

  • recvtype: 接收缓冲区元素的数据类型(句柄)。

  • root: 发送进程的等级(整数)。

  • comm: 通信器(句柄)。

  • info: 信息(句柄,持久化)。

17.2.311.3. 输出参数

  • recvbuf: 接收缓冲区的地址(选项)。

  • request: 请求(句柄,仅限非阻塞模式)。

  • ierror: 仅限Fortran:错误状态(整数)。

17.2.311.4. 描述

MPI_ScatterMPI_Gather 的逆操作。

结果相当于根节点执行了n次发送操作,

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

并且每个进程执行了一次接收操作,

MPI_Recv(recvbuf, recvcount, recvtype, i, ...).;

另一种描述方式是根进程通过MPI_Send(sendbuf, sendcount * n, sendtype, ...)发送消息。该消息被分割为n个等长的片段,第i个片段被发送给组中的第i个进程,每个进程按上述方式接收此消息。

对于所有非根进程,发送缓冲区将被忽略。

根进程中与sendcountsendtype关联的类型签名必须与所有进程中recvcountrecvtype关联的类型签名相等(但类型映射可以不同)。这意味着发送的数据量必须等于接收的数据量,在每个进程与根进程之间成对匹配。发送方和接收方之间仍允许使用不同的类型映射。

该函数的所有参数在进程root上都是有效的,而在其他进程上,只有参数recvbufrecvcountrecvtyperootcomm是有效的。参数rootcomm在所有进程上的值必须相同。

计数和类型的指定不应导致根位置被多次读取。

理由:虽然并非必需,但施加最后一项限制是为了与MPI_Gather保持对称性,因为后者对应的限制(多写限制)是必要的。

示例: MPI_Gather 手册页中示例1的反向操作。将每组100个整数的数据从根进程分散到组中的每个进程。

MPI_Comm comm;
int gsize,*sendbuf;
int root, rbuf[100];
...
MPI_Comm_size(comm, &gsize);
sendbuf = (int *)malloc(gsize*100*sizeof(int));
...
MPI_Scatter(sendbuf, 100, MPI_INT, rbuf, 100,
            MPI_INT, root, comm);

17.2.311.5. 使用原地选项

当通信器为内部通信器时,可以执行原地分散操作(输出缓冲区同时用作输入缓冲区)。将变量MPI_IN_PLACE作为根进程recvbuf的值。在这种情况下,recvcountrecvtype将被忽略,且根进程不会向自身发送数据。

请注意,MPI_IN_PLACE是一种特殊类型的值;其使用限制与MPI_BOTTOM相同。

由于原地(in-place)选项将接收缓冲区转换为发送-接收缓冲区,包含INTENT的Fortran绑定必须将其标记为INOUT,而非OUT。

17.2.311.6. 当通信器为跨通信器时

当通信器是跨通信器时,第一组中的根进程会向第二组中的所有进程发送数据。第一组定义了根进程。该进程使用MPI_ROOT作为其root参数的值。其余进程使用MPI_PROC_NULL作为它们的root参数值。第二组中的所有进程使用第一组中该根进程的秩作为它们root参数的值。第一组中根进程的接收缓冲区参数必须与第二组中进程的接收缓冲区参数保持一致。

17.2.311.7. 错误

几乎所有MPI例程都会返回一个错误值;C语言例程通过函数返回值返回,Fortran例程则通过最后一个参数返回。

在返回错误值之前,会调用与通信对象(如通信器、窗口、文件)关联的当前MPI错误处理程序。如果MPI调用未关联任何通信对象,则该调用被视为附加到MPI_COMM_SELF,并将调用关联的MPI错误处理程序。当MPI_COMM_SELF未初始化时(即在MPI_Init/MPI_Init_thread之前、MPI_Finalize之后,或仅使用会话模型时),错误会触发初始错误处理程序。初始错误处理程序可通过在使用世界模型时调用MPI_Comm_set_errhandler来修改MPI_COMM_SELF,或通过mpiexec的mpi_initial_errhandler命令行参数,或MPI_Comm_spawn/MPI_Comm_spawn_multiple的info键来设置。如果未设置其他适当的错误处理程序,则MPI I/O函数将调用MPI_ERRORS_RETURN错误处理程序,而其他所有MPI函数将调用MPI_ERRORS_ABORT错误处理程序。

Open MPI 包含三个可使用的预定义错误处理器:

  • MPI_ERRORS_ARE_FATAL 导致程序中止所有连接的MPI进程。

  • MPI_ERRORS_ABORT 一个可在通信器、窗口、文件或会话上调用的错误处理程序。当在通信器上调用时,其行为类似于在该通信器上调用MPI_Abort。如果在窗口或文件上调用,则行为类似于在包含对应窗口或文件中进程组的通信器上调用MPI_Abort。如果在会话上调用,则仅中止本地进程。

  • MPI_ERRORS_RETURN 向应用程序返回一个错误代码。

MPI应用程序也可以通过调用以下方式实现自己的错误处理程序:

请注意,MPI不保证MPI程序在出现错误后能够继续运行。

查看MPI手册页获取完整的MPI错误代码列表。

有关更多信息,请参阅MPI-3.1标准中的错误处理部分。