【问题标题】:MPI_Reduce doesn't work as expectedMPI_Reduce 没有按预期工作
【发布时间】:2012-11-19 21:36:58
【问题描述】:

我对 MPI 很陌生,我正在尝试使用 MPI_Reduce 来查找整数数组的最大值。我有一个大小为arraysize 的整数数组arr,这是我的代码:

MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &number_of_processes);
MPI_Comm_rank(MPI_COMM_WORLD, &my_process_id);
MPI_Bcast(arr, arraysize, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Reduce(arr, &result, arraysize, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);

if(!my_process_id){
    printf("%d", result);
}

MPI_Finalize();

我的程序在 8 个进程上编译并运行,没有任何问题,但是,屏幕上没有打印任何内容。出于调试目的,我将条件更改为if(my_process_id)(没有!)并运行。然后我得到一个奇怪的输出,例如00030000,其中 3 可能不确定地位于此列表中的任何位置。 3 是我的数组的第一个值(但不是最大值)。我一般都了解并行编程(不是专家,但我通常知道我在做什么)但我对 MPI 很陌生,因为我可能会犯一个明显的错误。我在网上看到的所有教程都有与我相似的代码示例,我不知道我做错了什么。

谢谢,

可以。

【问题讨论】:

    标签: c mpi openmpi reduction


    【解决方案1】:

    MPI_Reduce 完全按照它应该的方式工作。没有按照应有的方式使用它。

    MPI_Reduce 执行element-wise 数据缩减,分布在 MPI 作业的等级中。源缓冲区和目标缓冲区都应该是大小为arraysize 的数组,例如:

    int arr[arraysize];
    int result[arraysize];
    
    // Fill local arr with meaningful data
    ...
    // Perform reduction
    MPI_Reduce(arr, result, arraysize, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
    

    MPI_Reduce 的作用如下:

    result[0] = max(arr_0[0], arr_1[0], ..., arr_(N-1)[0]);
    result[1] = max(arr_0[1], arr_1[1], ..., arr_(N-1)[1]);
    ...
    result[arraysize-1] = max(arr_0[arraysize-1], ..., arr_(N-1)[arraysize-1]);
    

    其中arr_0 是排名0 中arr 的副本,arr_1 是排名1 中arr 的副本,依此类推。

    MPI_Bcast 的组合,然后是 MPI_MAX 的缩减,绝对没有,因为 arr 的所有副本在广播和元素应用后将具有相同的值 -明智的max 减少只会产生相同的值。更糟糕的是,我假设您的代码中的result 是一个标量整数变量,因此MPI_Reduce 将覆盖arraysize-1 元素超过result 并且很可能会破坏堆栈帧,覆盖排名中my_process_id 的值0 所以它不再是 0 (因此没有打印任何内容)并在之后崩溃排名 0。当然,这完全取决于局部变量在堆栈中的排列方式——其影响可能没有我描述的那么严重。

    如果你想找到一个数组的最大值,你应该首先使用MPI_Scatter分配它,然后使用MPI_Reduce进行元素归约,然后对结果进行另一次归约:

    int elements_per_proc = arraysize/number_of_processes;
    int arr[arraysize];
    int subarr[elements_per_proc];
    int partres[elements_per_proc];
    
    // Distribute the array
    MPI_Scatter(arr, elements_per_proc, MPI_INT,
                subarr, elements_per_proc, MPI_INT, 0, MPI_COMM_WORLD);
    
    // Perform element-wise max reduction
    MPI_Reduce(subarr, partres, elements_per_proc, MPI_INT,
               MPI_MAX, 0, MPI_COMM_WORLD);
    
    // Take the highest of the partial max values
    result = partres[0];
    for (int i = 1; i < elements_per_proc; i++)
       if (partres[i] > result) result = partres[i];
    

    现在你有了result中最大元素的值。

    甚至更好:

    int localmax;
    
    // Distribute the array
    MPI_Scatter(arr, elements_per_proc, MPI_INT,
                subarr, elements_per_proc, MPI_INT, 0, MPI_COMM_WORLD);
    
    // Find the maximum element of the local subarray
    localmax = subarr[0];
    for (int i = 1; i < elements_per_proc; i++)
       if (subarr[i] > localmax) localmax = subarr[i];
    
    // Perform global max reduction
    MPI_Reduce(&localmax, &result, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
    

    【讨论】:

    • 好的,一开始我有很多错误,经过几个小时试图理解发生了什么,我终于明白了 reduce/scatter/gather 的一般工作原理。谢谢
    • @canpoyrazoğlu,我真的建议您从here 下载 MPI 标准的副本。与其他一些枯燥且技术性很强的标准不同,这本书几乎是一本包含许多有用示例和大量解释的书。
    猜你喜欢
    • 2021-10-19
    • 2020-03-18
    • 2012-06-14
    • 2014-11-15
    • 1970-01-01
    • 2012-07-02
    • 2011-09-07
    • 2013-03-03
    • 2015-05-18
    相关资源
    最近更新 更多