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

MPI-IO中mpi_file_write_all异常排查:替换mpi_file_write后结果错误

MPI-IO集体写(MPI_File_write_all)数据顺序错误问题排查

你遇到的这个问题其实戳中了MPI-IO里独立写和集体写最核心的差异点——两者对文件视图的要求完全不一样,尤其是当你用到自定义索引类型的时候,集体写的规则要严格得多。

一、MPI_File_write 和 MPI_File_write_all 的核心区别

  • 独立写(MPI_File_write):每个进程各干各的,不需要和其他进程同步,每个进程的文件视图只作用于自身的读写操作,系统会自行处理并发写入的冲突(只要你设计的偏移不重叠,就不会出问题)。你之前用独立写正常,就是因为每个进程自己定义了专属的位移规则,各自写自己的区域,互不干扰。
  • 集体写(MPI_File_write_all):所有参与的进程必须同时调用这个函数,而且所有进程的文件视图定义必须全局一致。MPI会把集体写当成一个整体操作,基于统一的视图逻辑来分配每个进程的写入位置——如果每个进程的视图规则(比如你这里的自定义索引类型的位移)不一样,就会导致数据写入的重叠和顺序混乱,也就是你看到的od -f结果错乱的情况。

二、你的代码问题出在哪?

看你的CREATE_TYPE子程序,每个进程的DISPLACEMENTS数组都是完全不同的:进程0的位移是[0,5,2,3],进程1是[4,1,6,7],以此类推。这种“各玩各的”位移规则在独立写时没问题,但集体写时,MPI会默认所有进程的视图是统一的,这就相当于每个进程都按照自己的规则往同一个逻辑视图里写,结果自然就乱了。

三、修改方案:适配集体写的规则

要让MPI_File_write_all正常工作,你需要调整自定义数据类型的设计,让每个进程的文件视图对应到文件的全局逻辑结构。这里给你一种适配原有需求的修改版本:

修改后的完整代码

PROGRAM INDEXED
USE MPI
IMPLICIT NONE
REAL :: A(4)
INTEGER :: INDEXTYPE,FH,IERR,L,N
INTEGER(KIND=MPI_OFFSET_KIND) :: OFFSET
CHARACTER(LEN=MPI_MAX_LIBRARY_VERSION_STRING) :: VERSION
INTEGER :: MY_RANK, NUM_PROCS

N=4
A(1)=1.0
A(2)=2.0
A(3)=3.0
A(4)=4.0

CALL MPI_INIT(IERR)
CALL MPI_COMM_RANK(MPI_COMM_WORLD, MY_RANK, IERR)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD, NUM_PROCS, IERR)
CALL MPI_GET_LIBRARY_VERSION(VERSION,L,IERR)
IF(MY_RANK == 0) WRITE(*,*)TRIM(VERSION)

! 创建全局一致的索引类型,每个进程的位移对应全局文件位置
CALL CREATE_TYPE(INDEXTYPE,N)

CALL MPI_FILE_OPEN(MPI_COMM_WORLD, "TEST", &
MPI_MODE_RDWR+MPI_MODE_CREATE+MPI_MODE_DELETE_ON_CLOSE, MPI_INFO_NULL,FH,IERR)
CALL MPI_CHECK_CALL(IERR)

! 集体写时,视图起始偏移设为0,自定义类型的位移直接对应全局文件的REAL单位位置
OFFSET=0
CALL MPI_FILE_SET_VIEW(FH, OFFSET,MPI_REAL, &
INDEXTYPE,'NATIVE', &
MPI_INFO_NULL, IERR)
CALL MPI_CHECK_CALL(IERR)

! 切换为集体写调用
CALL MPI_FILE_WRITE_ALL(FH,A,N,MPI_REAL, &
MPI_STATUS_IGNORE,IERR)
CALL MPI_CHECK_CALL(IERR)

CALL MPI_FILE_CLOSE(FH,IERR)
CALL MPI_CHECK_CALL(IERR)
CALL MPI_TYPE_FREE(INDEXTYPE, IERR) ! 记得释放已提交的MPI类型
CALL MPI_FINALIZE(IERR)
END PROGRAM INDEXED

SUBROUTINE CREATE_TYPE(DATARES_TYPE,N)
USE MPI
IMPLICIT NONE
INTEGER, INTENT(OUT) :: DATARES_TYPE
INTEGER, INTENT(IN) :: N
INTEGER :: IERR, MY_RANK
INTEGER, ALLOCATABLE :: BLOCKLENS(:), DISPLACEMENTS(:)

ALLOCATE(BLOCKLENS(N))
ALLOCATE(DISPLACEMENTS(N))
BLOCKLENS = 1

CALL MPI_COMM_RANK(MPI_COMM_WORLD, MY_RANK, IERR)

! 关键修改:每个进程的位移是全局文件中的位置(以MPI_REAL为单位)
! 所有进程都知道完整的类型结构,只是每个进程只写入自己对应的那部分位移
SELECT CASE(MY_RANK)
CASE(0)
    DISPLACEMENTS = [0,5,2,3]
CASE(1)
    DISPLACEMENTS = [4,1,6,7]
CASE(2)
    DISPLACEMENTS = [8,9,14,11]
CASE(3)
    DISPLACEMENTS = [12,13,10,15]
END SELECT

CALL MPI_TYPE_INDEXED(N, BLOCKLENS, DISPLACEMENTS, &
MPI_REAL, DATARES_TYPE, IERR)
CALL MPI_CHECK_CALL(IERR)
CALL MPI_TYPE_COMMIT(DATARES_TYPE, IERR)
CALL MPI_CHECK_CALL(IERR)

DEALLOCATE(BLOCKLENS)
DEALLOCATE(DISPLACEMENTS)
END SUBROUTINE

SUBROUTINE MPI_CHECK_CALL(IERR)
USE MPI
IMPLICIT NONE
INTEGER, INTENT(IN) :: IERR
INTEGER :: NERR, RESULTLEN
CHARACTER(LEN=MPI_MAX_ERROR_STRING) :: SERR
IF(IERR /= MPI_SUCCESS) THEN
    CALL MPI_ERROR_STRING(IERR,SERR,RESULTLEN,NERR)
    WRITE(*,*)TRIM(SERR)
    CALL BACKTRACE
END IF
END SUBROUTINE

四、额外注意事项

  • OpenMPI 3.0对集体IO的支持是稳定的,但要确保所有进程的MPI_File_set_view参数(数据类型、数据表示、起始偏移)逻辑一致——即使每个进程写入的位置不同,也要基于同一个全局视图规则。
  • 集体IO的优势是性能(尤其是大规模进程时),但代价是严格的同步和视图一致性要求,这是和独立IO最本质的区别。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:19:00