【问题标题】:How to add all the values inside an 2d array using MPI如何使用 MPI 在二维数组中添加所有值
【发布时间】:2021-06-22 13:57:55
【问题描述】:

我正在尝试使用 MPI(赋值)在 C 中构建具有多维数组的程序。

下面的程序运行但在 2 个输出行中给出了错误的值。 a 是一个多维数组。我不包含任何 0 值。但是第二个输出行是partial process: values are 0 and 0。为什么打印0值,我的a数组中没有0值。

这是我的基本程序

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
// size of array
#define n 6

int a[6][2] = { {2,3},{51,55},{88,199},{335,34534},{678,683},{98,99} };

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

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
        for (i = 0; i < elements_per_process; i++)
            printf("master process: values are %d and %d\n", a[i][0], a[i][1]);

        // 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;
        }

    }
    // 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 useless_fornow = -1;
        for (int i = 0; i < n_elements_recieved; i++) {
            printf("partial process: values are %d and %d \n", a2[i][0], a2[i][1]);
        }
        // sends the partial sum to the root process
        MPI_Send(&useless_fornow, 1, MPI_INT,
            0, 0, MPI_COMM_WORLD);
    }

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

    return 0;
}

这是输出:

部分过程:值为678和683

部分过程:值为0和0

主进程:值为 2 和 3

主进程:值为 51 和 55

部分过程:值为 88 和 199

部分过程:值为0和0

我正在使用此命令mpiexec.exe -n 3 Project1.exe 使用 3 个进程运行它

【问题讨论】:

    标签: c performance parallel-processing mpi hpc


    【解决方案1】:

    master发送&amp;a[index]给其他进程,即:

    • 对于进程 1,索引为 2,所以 master 发送的是{88,199}
    • 对于进程 2,索引为 4,因此主控发送的是 {678,683}

    因此,要发送不同的元素,您需要修复索引计算。

    在第二个MPI_Recv

    MPI_Recv(&a2, n_elements_recieved, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
    

    您指定应将要接收的元素复制到的位置是&amp;a2,它是二维数组a2 的开头。您还表示您希望收到n_elements_recieved。所以 master 向每个进程发送一个数组,每个进程都期望接收一个数组,到目前为止一切顺利。问题在于您打印收到的数据的逻辑,即:

    for (int i = 0; i < n_elements_recieved; i++) {
        printf("partial process: values are %d and %d \n", a2[i][0], a2[i][1]);
    }
    

    您正在按列打印,但您收到的是一维数组而不是二维数组。

    IMO 您可以简单地采取以下措施:

    每个进程首先收到他们将在下一次MPI_Recv 调用中收到的元素总数:

    MPI_Recv(&n_elements_recieved, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
    

    然后他们分配一个具有该大小的数组:

    int *tmp = malloc(sizeof(int) * n_elements_recieved);
    

    然后他们收到数据:

    MPI_Recv(tmp, n_elements_recieved, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
    

    最后打印数组上的所有元素:

    for(int i = 0; i < n_elements_recieved; i++)
       printf("partial process: values are %d \n", tmp[i]);
    

    如果您希望 master 进程将整个二维数组发送给所有其他进程,您可以使用MPI_Bcast

    将消息从具有“root”等级的进程广播到所有其他进程 沟通者的进程

    您可以利用您的二维数组在内存中连续分配的事实,并执行单个MPI_Bcast 来广播二维数组,这大大简化了代码,如您所见:

    #include <mpi.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char* argv[])
    {
        int pid, np;
        MPI_Status status;
        MPI_Init(&argc, &argv);
        MPI_Comm_rank(MPI_COMM_WORLD, &pid);
        MPI_Comm_size(MPI_COMM_WORLD, &np);
    
        int rows = (pid == 0) ? 6 : 0;
        int cols = (pid == 0) ? 2 : 0;    
        MPI_Bcast(&rows, 1, MPI_INT, 0, MPI_COMM_WORLD);
        MPI_Bcast(&cols, 1, MPI_INT, 0, MPI_COMM_WORLD);
        printf("%d, %d\n",rows, cols);
     
        int a[6][2];
        if(pid == 0){
        // just simulating some data.
            int tmp[6][2] = { {2,3},{51,55},{88,199},{335,34534},{678,683},{98,99} };
            for(int i = 0; i < 6; i++)
               for(int j = 0; j < 2; j++)
                  a[i][j] = tmp[i][j];
        }
        MPI_Bcast(&a, rows * cols, MPI_INT, 0, MPI_COMM_WORLD);
        MPI_Finalize();
    
        return 0;
    }
    

    每个进程不需要 3 个 MPI_Send/MPI_Recv,所有进程只需要 3 个MPI_Bcast

    【讨论】:

      猜你喜欢
      • 2014-06-23
      • 1970-01-01
      • 2019-08-12
      • 2019-03-07
      • 1970-01-01
      • 2012-03-05
      • 2018-10-30
      • 1970-01-01
      相关资源
      最近更新 更多