如何使用 MPI 在 C 中对二维数组求和

How to sum a 2D array in C using MPI

这是我用来对一维数组中的所有值求和的程序,它工作正常。但是我如何修改它以在二维数组上工作?假设变量 a 类似于 a = { {1,2}, {3,4}, {5,6} };.

我尝试了一些解决方案,但它们都不起作用,所以有人可以解释一些重要的更改以使其也与 2D 数组兼容。

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>

// size of array
#define n 10

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

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

int main(int argc, char* argv[])
{

    int pid, np,
        elements_per_process,
        n_elements_recieved;
    // np -> no. of processes
    // pid -> process id

    MPI_Status status;

    // Creation of parallel processes
    MPI_Init(&argc, &argv);

    // find out process ID,
    // and how many processes were started
    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
            // to child processes to calculate
            // their partial sums
            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);
        }

        // master process add its own sub array
        int sum = 0;
        for (i = 0; i < elements_per_process; i++) 
            sum += a[i];

        // collects partial sums from other processes
        int tmp;
        for (i = 1; i < np; i++) {
            MPI_Recv(&tmp, 1, MPI_INT,
                MPI_ANY_SOURCE, 0,
                MPI_COMM_WORLD,
                &status);
            int sender = status.MPI_SOURCE;
            sum += tmp;
        }

        // prints the final sum of array
        printf("Sum of array is : %d\n", sum);



    }
    // slave 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
        int partial_sum = 0;
        for (int i = 0; i < n_elements_recieved; i++)
            partial_sum += a2[i];

        // sends the partial sum to the root process
        MPI_Send(&partial_sum, 1, MPI_INT,
            0, 0, MPI_COMM_WORLD);
    }

    // cleans up all MPI state before exit of process
    MPI_Finalize();




    return 0;
}

您可以使用 MPI_Reduce 代替 MPI_Send/MPI_Recv 来简化很多事情:

Reduces values on all processes to a single value

可以找到关于该例程的很好的教程 here

因此每个进程都包含一个数组(例如, 进程 0 { 1, 2, 3, 4, 5} 和进程 1 {6, 7, 8, 9, 10 })并执行该数组的部分求和。最后,每个进程使用 MPI_Reduce 将所有部分和求和为主进程可用的单个值(它也可能是另一个进程)。看看这个例子:

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[]){
    int np, pid;
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &pid);
    MPI_Comm_size(MPI_COMM_WORLD, &np);

    int partial_sum = 0;
    if (pid == 0) {
        int a[] = { 1, 2, 3, 4, 5};
        for(int i = 0; i < 5; i++)
           partial_sum += a[i];        
    }
    else  if (pid == 1){
        int a[] = {6, 7, 8, 9, 10};
        for(int i = 0; i < 5; i++) 
           partial_sum += a[i];
    }
    int sum;
    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;
}

此代码仅适用于 2 个进程(有点傻(但我用它来展示 MPI_Reduce.

的使用

I tried few solutions but they are not working, so can someone explain few important changes to make to make it compatible with 2D array also.

如果您调整代码以使用我所展示的 MPI_Reduce,那么它是一维数组还是二维数组并不重要,因为您将首先将部分求和转换为单个值,然后性能降低。

或者,您也可以将每一行分配给一个进程,然后对整个数组进行归约,然后 master 进程对结果数组进行求和。

一个例子:

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[]){
    int np, pid;
    MPI_Status status;
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &pid);
    MPI_Comm_size(MPI_COMM_WORLD, &np);

    int partial_sum = 0;
    int size = 5;
    int a[5] = {1, 2, 3 , 4, 5};
    int sum[5] = {0};
    MPI_Reduce(&a, &sum, size, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);

    if (pid == 0){
       int total_sum = 0;
       for(int i = 0; i < size; i++)
           total_sum += sum[i];
       printf("Sum of array is : %d\n", total_sum);
    }

    MPI_Finalize();
    return 0;
}

输出(两个进程):

Sum of array is : 30