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

Fortran中使用MPI_Allgather同步多数组数据出错,求排查

MPI_Allgather使用错误导致通信异常问题排查

问题描述

需要将多数组任务分配给不同进程计算,之后让所有进程同步数据,使用MPI_Allgather后结果不符合预期。示例代码如下:

program main
use mpi
implicit none

integer           :: nproc,rank,ierr,i
integer,parameter :: n = 3
integer,parameter :: m = 2
double precision  :: x(n,m),y(n,m),z(m)

! Initializing MPI
call mpi_init(ierr)
call mpi_comm_rank(mpi_comm_world, rank,  ierr)
call mpi_comm_size(mpi_comm_world, nproc, ierr)

! Initial values for x
x = 0.0
y = 1.0

! Do the following m times
do i = 1,m
    
    ! Distribute work in 2 processes
    if (rank == 0) then
        x(:,i) = x(:,i) + i
    end if

    if (rank == 1) then
        y(:,i) = y(:,i) * (i+1.0)
    end if

    ! MPI barrier
    call mpi_barrier(mpi_comm_world, ierr)

    ! Gathering (MPI), so all processes have the same data
    call mpi_allgather(mpi_in_place, n, mpi_double_precision, x(:,i), n, mpi_double_precision, mpi_comm_world, ierr)
    call mpi_allgather(mpi_in_place, n, mpi_double_precision, y(:,i), n, mpi_double_precision, mpi_comm_world, ierr)
    
    ! MPI barrier
    call mpi_barrier(mpi_comm_world, ierr)
    
    ! Using data from both processes
    z(i) = sum(x(:,i)) + sum(y(:,i))

    if (rank == 0)  then
        print *, i, z(i)
    end if

end do

! Finalizing MPI
call mpi_finalize(ierr)

end program main

预期进程0输出:

1   9.00000000000000
       2   15.0000000000000

实际结果错误,需排查问题原因。

错误原因分析

  • MPI_Allgather功能与使用场景不匹配
    MPI_Allgather的作用是将每个进程发送缓冲区的数据,收集到所有进程的接收缓冲区中,接收缓冲区总容量需要等于进程数 × 发送数据量。但你的需求是让所有进程获取单个进程计算的完整数据(x(:,i)由进程0计算,y(:,i)由进程1计算),这种场景下MPI_Bcast(广播)才是正确选择,MPI_Allgather会将多个进程的不同数据拼接,导致数据混乱。

  • MPI_IN_PLACE使用错误
    MPI_IN_PLACE仅适用于发送缓冲区与接收缓冲区重叠,且所有进程都有需要汇总的有效数据的场景。但这里进程1的x(:,i)是初始值0,进程0的y(:,i)是初始值1,用MPI_IN_PLACE会导致有效数据被无效的初始值覆盖。

  • 接收缓冲区容量不足
    调用MPI_Allgather时,接收缓冲区x(:,i)仅能容纳n个元素,但实际需要接收nproc × n个元素(每个进程发送n个double),这会导致缓冲区溢出或数据覆盖,破坏原有有效数据。

修正方案

将MPI_Allgather替换为MPI_Bcast,针对每个数组的计算进程进行广播:

program main
use mpi
implicit none

integer           :: nproc,rank,ierr,i
integer,parameter :: n = 3
integer,parameter :: m = 2
double precision  :: x(n,m),y(n,m),z(m)

! Initializing MPI
call mpi_init(ierr)
call mpi_comm_rank(mpi_comm_world, rank,  ierr)
call mpi_comm_size(mpi_comm_world, nproc, ierr)

! Initial values for x
x = 0.0
y = 1.0

! Do the following m times
do i = 1,m
    
    ! Distribute work in 2 processes
    if (rank == 0) then
        x(:,i) = x(:,i) + i
    end if

    if (rank == 1) then
        y(:,i) = y(:,i) * (i+1.0)
    end if

    ! MPI barrier
    call mpi_barrier(mpi_comm_world, ierr)

    ! 广播进程0计算的x(:,i)到所有进程
    call mpi_bcast(x(:,i), n, mpi_double_precision, 0, mpi_comm_world, ierr)
    ! 广播进程1计算的y(:,i)到所有进程
    call mpi_bcast(y(:,i), n, mpi_double_precision, 1, mpi_comm_world, ierr)
    
    ! MPI barrier(可选,因为MPI_Bcast本身是同步操作)
    call mpi_barrier(mpi_comm_world, ierr)
    
    ! Using data from both processes
    z(i) = sum(x(:,i)) + sum(y(:,i))

    if (rank == 0)  then
        print *, i, z(i)
    end if

end do

! Finalizing MPI
call mpi_finalize(ierr)

end program main

说明

  • MPI_Bcast会将指定根进程的数据发送到通信域内的所有进程,完美匹配你“单个进程计算,所有进程同步数据”的需求。
  • 原代码中的MPI_Barrier在MPI_Bcast后可省略,因为MPI_Bcast本身是阻塞式同步操作,所有进程会在广播完成后才继续执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 08:32:57