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

MPI Reduce计算数组部分和总和失效问题排查

问题分析与解决方案

原代码的核心错误

你的MPI_Reduce未正确工作,主要是这几个问题:

  1. MPI_Reduce的count参数错误
    你写的是MPI_Reduce(&partial_sum,&sum, n, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);,第三个参数n是数组总长度,但每个进程要归约的是单个整数(partial_sum),所以这里应该传1,不是n。传n会导致MPI尝试读取每个进程中从partial_sum开始的n个整数,超出内存范围后结果自然错误。

  2. 主进程的partial_sum未赋值
    主进程(pid=0)自己计算了部分和但存在sum里,而MPI_Reduce是把所有进程的partial_sum汇总到sum中。主进程的partial_sum初始为0,没把自己的部分和放进去,会导致归约时丢失主进程的计算贡献。

  3. 打印时机错误
    主进程在MPI_Reduce执行前就打印了sum,这时候还没完成归约,打印的只是自己单独计算的部分和,自然只有前半段的结果。必须等MPI_Reduce执行完再打印。

修正后的代码

// size of array
#define n 10

int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// Temporary array for other process
int a2[1000];

int main(int argc, char* argv[])
{
    int pid, np, elements_per_process, n_elements_recieved;

    int partial_sum = 0; //local sums
    int sum = 0;
    MPI_Status status;
    MPI_Init(&argc, &argv);

    MPI_Comm_rank(MPI_COMM_WORLD, &pid);
    MPI_Comm_size(MPI_COMM_WORLD, &np);

    // master process
    if (pid == 0) {
        int index, i;
        elements_per_process = n / np;

        // check if more than 1 processes are run
        if (np > 1) {
            // distributes the portion of array
            for (i = 1; i < np - 1; i++) {
                index = i * elements_per_process;
                MPI_Send(&elements_per_process,1, MPI_INT, i, 0,MPI_COMM_WORLD);
                MPI_Send(&a[index],elements_per_process, MPI_INT, i, 0,MPI_COMM_WORLD);
            }

            // last process adds remaining elements
            index = i * elements_per_process;
            int elements_left = n - index;

            MPI_Send(&elements_left,1, MPI_INT,i, 0,MPI_COMM_WORLD);
            MPI_Send(&a[index], elements_left,MPI_INT, i, 0, MPI_COMM_WORLD);
        }

        // 主进程把自己的部分和放到partial_sum里,用于后续归约
        for (i = 0; i < elements_per_process; i++)
            partial_sum += a[i];
    }
    // other processes
    else {
        MPI_Recv(&n_elements_recieved, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);

        // stores the received array segment
        // in local array a2
        MPI_Recv(&a2, n_elements_recieved,MPI_INT, 0, 0,MPI_COMM_WORLD, &status);

        // calculates its partial sum
        for (int i = 0; i < n_elements_recieved; i++)
            partial_sum += a2[i];
    }

    // 修正count参数为1,每个进程归约单个整数
    MPI_Reduce(&partial_sum,&sum, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);

    // 主进程在归约完成后打印结果
    if (pid == 0) {
        printf("Sum of array is : %d\n", sum);
    }

    MPI_Finalize();

    return 0;
}

关于MPI_Scatter处理可变长度数组的问题

如果想用MPI_Scatter简化代码,当数组长度不能被进程数整除时,用MPI_Scatterv(带v的版本,支持可变长度分发)。步骤如下:

  1. 主进程创建两个数组:

    • sendcounts:每个进程要接收的元素个数,比如n=10,np=3时,sendcounts = [4,3,3]
    • displs:每个进程对应的数组起始位移,比如displs = [0,4,7]
  2. 调用MPI_Scatterv分发数组,其他进程接收对应长度的元素。

示例代码片段(主进程部分):

int sendcounts[np];
int displs[np];
int elements_per_process = n / np;
int remainder = n % np;

for (int i=0; i<np; i++) {
    sendcounts[i] = elements_per_process;
    if (i < remainder) {
        sendcounts[i]++; // 前remainder个进程多拿一个元素
    }
}

displs[0] = 0;
for (int i=1; i<np; i++) {
    displs[i] = displs[i-1] + sendcounts[i-1];
}

// 分发数组,主进程用a,其他进程用a2
MPI_Scatterv(a, sendcounts, displs, MPI_INT, a2, sendcounts[pid], MPI_INT, 0, MPI_COMM_WORLD);

这样不管数组长度是奇数还是偶数,都能正确分发到各个进程,之后每个进程计算自己的partial_sum,再用MPI_Reduce汇总即可,比手动Send/Recv简洁很多。

内容的提问来源于stack exchange,提问作者howtofly-lab

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 21:57:53