MPI_Gather是最好的选择吗?

时间:2016-03-11 15:54:14

标签: fortran mpi gfortran

有4个进程,其中一个进程(0)是必须构建矩阵C的主进程,如下所示

-1  0  0 -1  0
 0 -1  0  0 -1
-1  1  1 -1  1
 1 -1  1  1 -1
-1  2  2 -1  2
 2 -1  2  2 -1
-1  3  3 -1  3
 3 -1  3  3 -1

为此,矩阵声明为REAL, DIMENSION(:,:), ALLOCATABLE :: C并用

分配
IF (myid == 0) THEN
        ALLOCATE(C(2*nprocs,-2:+2))
END IF

其中nprocs是进程数。流程0还设置C = -1。对于我第一次尝试的通信

CALL MPI_GATHER((/0.0+myid,0.0+myid/),&
              & 2,MPI_REAL,&
              & C(:,0),&
              & 2,MPI_REAL,&
              & 0,MPI_COMM_WORLD,ieri)

填写中心栏,这很有用。 然后我尝试了

CALL MPI_GATHER((/myid, myid, myid, myid/),&
              & 4,MPI_REAL,&
              & (/C(1:2*nprocs:2,-1),C(2:2*nprocs:2,-2),C(1:2*nprocs:2,+2),C(2:2*nprocs:2,+1)/),&
              & 4,MPI_REAL,&
              & 0,MPI_COMM_WORLD,ierr)

填写其他列,但它不起作用,给出如下错误

Fortran runtime error: Index '1' of dimension 1 of array 'c' outside of expected range (140735073734712:140735073734712).

为了理解原因,我试图通过调用

单独填写第一列
CALL MPI_GATHER((/0.0-myid/),&
              & 1,MPI_REAL,&
              & C(1:2*nprocs:2,-2),&
              & 1,MPI_REAL,&
              & 0,MPI_COMM_WORLD,ierr)

但同样的事情或多或少发生了。

我通过为所有进程分配C来解决了这个问题(即无论进程ID如何)。为什么这会使通话工作?

在此之后我做了一点改变(在再次尝试填充所有列之前)只需将接收缓冲区放在(/.../)

CALL MPI_GATHER((/0.0-myid/),&
              & 1,MPI_REAL,&
              & (/C(1:2*nprocs:2,-2)/),&
              & 1,MPI_REAL,&
              & 0,MPI_COMM_WORLD,ieri)

但是这会使调用无效(没有错误,但C中的一个元素都没有更改)。

希望有人能向我解释

  • 接收缓冲区中的构造函数(/.../)出了什么问题?
  • 为什么必须在非root进程中分配接收缓冲区?
  • 是否有必要使用mpi_gatherv来完成任务?
  • 有没有更好的方法来构建这样的矩阵?

修改 是否可以使用MPI派生的数据类型来构建矩阵?

1 个答案:

答案 0 :(得分:1)

如果您还没有这样做,请首先使用use mpi代替include mpif.h。其中一些错误可能是由此发现的。

您不能将数组构造函数用作接收缓冲区。为什么?构造函数创建的数组是一个表达式。你不能在需要变量的地方使用它。

您无法将1+1传递给更改为参数的子例程。 1+1是一个表达式,如果要更改它,则需要一个变量。

其次,必须分配您编写或从中读取的每个数组。在MPI_Gather中,所有非根进程都会忽略接收缓冲区。但是当您从C(1:2*nprocs:2,-2)中的C数组创建子数组时,必须分配这样的数组。这是Fortran的东西,而不是MPI。

如果从每个排名收到的元素数量相同,您可以使用MPI_Gather,则不需要MPI_Gatherv

您可以考虑将数据接收到1D缓冲区并根据需要重新排序。另一种选择是将其沿最后一个维度分解。