mpi_recv 只接收 mpi_send 发送的一半数据?完全糊涂

Posted

技术标签:

【中文标题】mpi_recv 只接收 mpi_send 发送的一半数据?完全糊涂【英文标题】:mpi_recv only recieving half of the data sent by mpi_send ? Utterly confused 【发布时间】:2018-05-03 07:22:41 【问题描述】:

我正在用 fortran 学习 mpi。我写了一个简单的代码如下。

program arraypractice
use mpi
    integer pid, np, ierr, arraysize, i,msg, status(mpi_status_size)       
    integer dcount
    real*8  f(10), f1(10)

    call mpi_init(ierr)
    call mpi_comm_size(mpi_comm_world, np, ierr)
    call mpi_comm_rank(mpi_comm_world, pid, ierr)

    if(pid==0) then
          do i = 1, 10
          f(i)=float(i)
          enddo
    endif

        msg = 1

    if(pid==0) then
         call mpi_send(f(1),6,mpi_real,1,msg,mpi_comm_world,ierr)
    endif

    if(pid==1) then
        call mpi_recv(f1(1),6,mpi_real,0,msg,mpi_comm_world,status,ierr)

        call mpi_get_count(status,mpi_real,dcount,ierr)
        print *,dcount
        do i= 1, 6
          print *,f1(i)
        enddo
    endif

    call mpi_finalize(ierr)
end

我正在使用“mpif90”命令编译代码,然后在我的带有 Arch Linux 的 i5 双核笔记本电脑上使用“mpirun -n 2 a.out”命令运行它。我的输出看起来像,

          6
   1.0000000000000000     
   2.0000000000000000     
   3.0000000000000000     
   0.0000000000000000     
   0.0000000000000000     
   0.0000000000000000

我完全不明白为什么最后 3 个数字没有更新。每次 mpi_recv 只接收 mpi_send 发送的数据的一半。我希望输出是

          6
   1.0000000000000000     
   2.0000000000000000     
   3.0000000000000000     
   4.0000000000000000     
   5.0000000000000000     
   6.0000000000000000

任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

数组元素的类型与您提供给 MPI 调用的数据类型之间存在类型不匹配。 real*8 表示 64 位双精度数,而 MPI_REAL 对应(通常)32 位单精度类型 real。因此,MPI 只发送前半部分数据。

要么去掉 real*8 中的 *8 以使用单精度,要么将 MPI_REAL 替换为 MPI_DOUBLE_PRECISIONMPI_REAL8。第二种 MPI 数据类型 (MPI_REAL8) 是可选的,可能并非在所有 MPI 库中都可用。

【讨论】:

另请注意 real*8 不是也从来不是标准 Fortran - 我强烈建议您了解 kind 机制。【参考方案2】:

您还应该注意,MPI 保证仅适用于 Fortran 77 和 C。不保证适用于 Fortran 90(或更高版本)或 C++。 MPI 不像普通库,它直接与内存布局混淆,并且可以覆盖与您所做的 MPI 调用无关的局部变量。例如,我在 MPI 中发生了崩溃,只是因为我有一个局部变量 integer i。这个变量在我对 MPI 的调用中没有任何作用。当我偶然发现integer, save :: i(所以不在堆栈上)时,一切正常!

【讨论】:

这是不正确的。请参阅mpi-forum.org/docs/mpi-3.0/mpi30-report.pdf 第 2.6.2 节,其中指出“当使用术语“Fortran”时,它表示 Fortran 90 或更高版本”。 C++ 支持也已发布,但现已弃用。 这是完全错误的。如果程序由于堆栈布局而改变行为,这是堆栈损坏的明显迹象。检查所有子程序和函数参数的正确性,尤其是它们的类型和种类。这是一种常见的错误类型,与 MPI 内部无关,仅与代码的正确性有关。显然,mpi 模块必须用于 Fortran 90,因为 Fortran 77 中没有模块。显然,mpi_f08 模块用于 Fortran 2008,它甚至是这样命名的。 MPI 甚至支持 Fortran 2008。

以上是关于mpi_recv 只接收 mpi_send 发送的一半数据?完全糊涂的主要内容,如果未能解决你的问题,请参考以下文章

MPI_Recv() 冻结程序,未从 C 中的 MPI_Send() 接收值

C++ 中的 MPI_Send MPI_Recv 段错误

MPI_SEND 占用大量虚拟内存

是否需要在对应的 MPI_Recv 之前调用 MPI_Send

使用 MPI_Send 和 MPI_Recv 实现 MPI_Scatter 的问题

关于MPI_Send与MPI_Recv语义