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

Fortran 2008中MPI_Op_create与MPI_Reduce自定义操作实现求助

问题描述

已在C语言中实现基于自定义操作的MPI归约,但在Fortran 2008中尝试时遇到困难。现有代码使用MPI_SUM可正常将4个MPI进程的rank值求和为全局总和6,但自定义操作实现的代码运行结果为3,寻求正确的Fortran 2008实现方案。

可用的MPI_SUM正确代码

program main
    use mpi_f08
    implicit none

    integer :: ierror, isize, irank
    integer :: local_value, global_value

    call MPI_INIT(ierror)
    call MPI_COMM_SIZE(MPI_COMM_WORLD, isize)
    call MPI_COMM_RANK(MPI_COMM_WORLD, irank)

    if (irank == 0) then
        local_value = irank
        global_value = 0
        call MPI_Reduce(local_value, global_value, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD, ierror)
        print *, "global_value", global_value
    else
        local_value = irank
        call MPI_Reduce(local_value, global_value, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD, ierror)
    end if

    call MPI_FINALIZE(ierror)
end program main

有问题的自定义操作代码

program main
    use mpi
    implicit none

    integer :: local_value, global_sum
    integer :: ierr, rank, size
    integer :: my_op

    call MPI_Init(ierr)
    call MPI_Comm_size(MPI_COMM_WORLD, size, ierr)
    call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierr)

    call MPI_Op_create(custom_sum_op, .true., my_op, ierr)

    if (rank == 0) then
        local_value = rank
        global_sum = 0
        call MPI_Reduce(local_value, global_sum, 1, MPI_INT, my_op, 0, MPI_COMM_WORLD, ierr)
        print *, "Global sum: ", global_sum
    else
        local_value = rank
        call MPI_Reduce(local_value, global_sum, 1, MPI_INT, my_op, 0, MPI_COMM_WORLD, ierr)
    endif

    call MPI_Finalize(ierr)

contains

subroutine custom_sum_op(res, a)
    integer, intent(inout) :: res
    integer, intent(in) :: a
    res = a + res
end subroutine custom_sum_op

end program main
解决方案与错误分析

错误原因

  1. 自定义操作子例程接口不符合MPI规范:Fortran的MPI自定义操作必须使用固定的四参数接口,而非仅两个参数。MPI需要通过额外参数处理数据长度、类型等信息,即使单元素归约也不能省略。
  2. 未释放自定义操作对象:创建的自定义操作my_op未调用MPI_Op_free释放,可能导致资源泄漏。

正确的Fortran 2008实现

program main
    use mpi_f08
    implicit none

    integer :: local_value, global_sum
    integer :: ierr, rank, size
    type(MPI_Op) :: my_op  ! 使用mpi_f08的类型而非整数句柄

    call MPI_Init(ierr)
    call MPI_Comm_size(MPI_COMM_WORLD, size, ierr)
    call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierr)

    ! 创建自定义归约操作,求和为结合性操作,设置为.true.
    call MPI_Op_create(custom_sum_op, .true., my_op, ierr)

    local_value = rank
    if (rank == 0) then
        global_sum = 0
        call MPI_Reduce(local_value, global_sum, 1, MPI_INT, my_op, 0, MPI_COMM_WORLD, ierr)
        print *, "Global sum: ", global_sum
    else
        ! 非根进程的recvbuf可使用任意变量,此处沿用global_sum不影响结果
        call MPI_Reduce(local_value, global_sum, 1, MPI_INT, my_op, 0, MPI_COMM_WORLD, ierr)
    endif

    ! 释放自定义操作对象
    call MPI_Op_free(my_op, ierr)
    call MPI_Finalize(ierr)

contains

! 符合MPI规范的自定义操作子例程接口
subroutine custom_sum_op(invec, inoutvec, len, datatype)
    use mpi_f08
    implicit none
    integer, intent(in) :: invec(*)        ! 输入数据向量
    integer, intent(inout) :: inoutvec(*)  ! 累加结果向量
    integer, intent(in) :: len             ! 数据元素长度
    type(MPI_Datatype), intent(in) :: datatype  ! 数据类型

    integer :: i

    ! 对每个元素执行求和累加
    do i = 1, len
        inoutvec(i) = inoutvec(i) + invec(i)
    end do
end subroutine custom_sum_op

end program main

关键修正点说明

  • 使用mpi_f08模块:提供Fortran 2008兼容的类型安全MPI接口,替代旧版的整数句柄。
  • 修正自定义操作接口:必须包含invec、inoutvec、len、datatype四个参数,MPI会自动传递这些信息,确保归约逻辑正确执行。
  • 释放自定义操作:调用MPI_Op_free释放创建的操作对象,避免资源泄漏。
  • 简化代码逻辑:将local_value = rank移到条件判断外,代码更简洁规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 10:13:17