You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Fortran90 MPI程序中如何从指定rank获取3D数组的单个元素值

解决方案

你遇到的问题核心是常规点对点通信需要收发两端主动调用通信接口,但无计算任务的进程不会进入通信逻辑,因此最优方案是使用MPI单边通信(RMA,远程内存访问),该方案不需要远端进程主动参与通信操作,仅需初始化阶段全局注册共享内存即可。

原方案报错原因

  • MPI_Sendrecv需要通信两端同时调用该接口,你仅在需要拉取数据的进程中调用,远端发送进程未执行对应通信调用,因此会出现消息截断、超时等错误。
  • 广播、集合通信要求通信域内所有进程同时调用,也不符合你的场景。

具体实现步骤

1. 全局初始化阶段(所有进程都执行,不需要放到if判断内)

所有进程分配完u数组后,创建MPI RMA窗口,将u数组的内存暴露给通信域内所有进程:

! 分配u数组后新增代码
INTEGER :: win
CALL MPI_Win_create(u, (ie-is+1)*(je-js+1)*(ke-ks+1)*8, 8, MPI_INFO_NULL, MPI_COMM_WORLD, win, ierr)

2. 在perform_some_action子程中拉取远端数据

需要获取其他rank的u数组值时,使用MPI_Get接口直接读取远端窗口内存即可:

subroutine perform_some_action(sendingRank, i_target, j_target, k_target, saveValueHere)
    implicit none
    include 'mpif.h'
    integer, intent(in) :: sendingRank, i_target, j_target, k_target
    real(8), intent(out) :: saveValueHere
    integer :: ierr, disp
    ! 提前保存各进程u数组的起始/结束索引,可作为全局变量或入参传递
    integer, save :: is_s, ie_s, js_s, je_s, ks_s, ke_s 
    ! 计算目标元素在远端进程u数组中的偏移量(适配Fortran列优先存储顺序)
    disp = (k_target - ks_s) * (ie_s - is_s + 1) * (je_s - js_s + 1) + (j_target - js_s) * (ie_s - is_s + 1) + (i_target - is_s)
    disp = disp * 8 ! 乘以双精度浮点数的字节数
    
    ! RMA同步
    CALL MPI_Win_fence(0, win, ierr)
    ! 拉取远端数据
    CALL MPI_Get(saveValueHere, 1, MPI_DOUBLE_PRECISION, sendingRank, disp, 1, MPI_DOUBLE_PRECISION, win, ierr)
    ! 同步确保数据拉取完成
    CALL MPI_Win_fence(0, win, ierr)
end subroutine

3. 程序结束前全局释放窗口

所有进程在MPI_Finalize前调用窗口释放接口:

CALL MPI_Win_free(win, ierr)

修改后的可运行示例代码

PROGRAM mpitest
USE mpi
IMPLICIT NONE

INTEGER :: ierr, npe, rank, win
INTEGER :: is,ie,js,je,ks,ke
REAL(8), dimension(:,:,:), allocatable :: u
REAL(8) :: saveValueHere
INTEGER :: disp ! 内存偏移量

CALL MPI_INIT( ierr )
CALL MPI_COMM_RANK( MPI_COMM_WORLD, rank, ierr )
CALL MPI_COMM_SIZE( MPI_COMM_WORLD, npe, ierr )

if(rank.eq.0) then
    is=1
    ie=2
    js=1
    je=2
    ks=1
    ke=2
else if(rank.eq.1) then
    is=3
    ie=4
    js=3
    je=4
    ks=3
    ke=4
endif

allocate(u(is:ie,js:je,ks:ke))
u=0.d0
if(rank.eq.0) then
    u(is,js,ks)=1.d0
    u(is,js,ke)=2.d0
    u(is,je,ks)=3.d0
    u(is,je,ke)=4.d0
    u(ie,js,ks)=5.d0
    u(ie,js,ke)=6.d0
    u(ie,je,ks)=7.d0
    u(ie,je,ke)=8.d0
else if(rank.eq.1) then
    u(is,js,ks)=11.d0
    u(is,js,ke)=12.d0
    u(is,je,ks)=13.d0
    u(is,je,ke)=14.d0
    u(ie,js,ks)=15.d0
    u(ie,js,ke)=16.d0
    u(ie,je,ks)=17.d0
    u(ie,je,ke)=18.d0
endif

! 所有进程创建RMA窗口
CALL MPI_Win_create(u, (ie-is+1)*(je-js+1)*(ke-ks+1)*8, 8, MPI_INFO_NULL, MPI_COMM_WORLD, win, ierr)

if(rank.eq.0) then
    write(*,*) 'get u(3,4,3)=13.d0 from rank 1 and save in saveValueHere'
    ! 计算rank1上u(3,4,3)的偏移量:rank1的ks=3, js=3, is=3
    disp = (3 - 3) * (4-3+1)*(4-3+1) + (4 - 3)*(4-3+1) + (3-3)
    disp = disp * 8
    ! 拉取数据
    CALL MPI_Win_fence(0, win, ierr)
    CALL MPI_Get(saveValueHere, 1, MPI_DOUBLE_PRECISION, 1, disp, 1, MPI_DOUBLE_PRECISION, win, ierr)
    CALL MPI_Win_fence(0, win, ierr)
    write(*,*) '拉取结果:saveValueHere = ', saveValueHere
endif

! 释放窗口
CALL MPI_Win_free(win, ierr)
deallocate(u)

CALL MPI_FINALIZE(ierr)

END PROGRAM mpitest

额外说明

  • 偏移量计算需要严格对应Fortran数组列优先的存储顺序,不要和C语言的行优先混淆。
  • 如果你的计算场景中多个进程同时拉取数据,MPI_Win_fence同步可以保证数据一致性,不需要额外处理。
  • 该方案完全不需要无计算任务的进程参与任何通信逻辑,仅需初始化和释放阶段执行两次全局调用即可,适配你的代码结构。

内容的提问来源于stack exchange,提问作者tre95

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 00:39:01