c - 如何在MPI中传递二维数组并使用C语言创建动态标签值?

标签 c parallel-processing mpi

我是 MPI 编程的新手。我有一个 8 x 10 数组,我需要用它来并行查找每一行的总和。在等级 0(进程 0)中,它将使用二维数组生成 8 x 10 矩阵。然后我将使用 tag 编号作为数组的第一个索引值(行号)。这样,我可以使用一个独特的缓冲区通过 Isend 发送。但是,我为 Isend 生成标签号的方法似乎不起作用。您能否查看以下代码并告诉我是否正确传递了二维数组和标签号。当我运行这段代码时,它在执行 rannk 1 后立即停止并等待。我在此示例中使用 3 个进程并使用命令 mpirun -np 3 test 请让我知道如何通过示例解决此问题(如果可能)。

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

int main (int argc, char *argv[])
{
        MPI_Init(&argc, &argv);
        int world_rank;
        MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
        int world_size;
        MPI_Comm_size(MPI_COMM_WORLD, &world_size);        
        int tag = 1;        
        int arr[8][10]; 
        MPI_Request request;
        MPI_Status status;
        int source = 0;
        int dest;

        printf ("\n--Current Rank: %d\n", world_rank);

        if (world_rank == 0)
        {
            int i = 0;
            int a, b, x, y;

            printf("* Rank 0 excecuting\n");

            for(a=0; a<8/(world_size-1); a++)//if -np is 3, this will loop 4 times
            {           
                for(b=0; b<(world_size-1); b++)//if -np is 3, this loops will loop 2 times
                {//So, if -np is 3, due to both of these loops, Isend will be called 8 times
                    dest = b+1;     
                    tag = a+b;//create a uniqe tag value each time, which can be use as first index value of array
                    //Error: This tag value passing to Isend doesn't seems to be workiing
                    MPI_Isend(&arr[tag][0], 10, MPI_INT, dest, tag, MPI_COMM_WORLD, &request);  
                }
            }

            for(x=0; x<8; x++)//Generating the whole 8 by 10 2D array
            {   
                i++;
                for ( y = 0; y < 10; y++ )
                {
                    arr[x][y] = i; 
                }   
            }               
        }
        else 
        {
            int a, b;                   
            for(b=1; b<=8/(world_size-1); b++)
            {
                int sum = 0;
                int i;
                MPI_Irecv(&arr[tag][0], 10, MPI_INT, source, tag, MPI_COMM_WORLD, &request);
                MPI_Wait (&request, &status);               
                        //Error: not getting the correct tag value
                for(i = 0; i<10; i++)
                {   
                    sum = arr[tag][i]+sum;
                }
                printf("\nSum is: %d at rank: %d and tag is:%d\n", sum, world_rank, tag);
            }           
        }
        MPI_Finalize();
}

最佳答案

标签问题是因为标签在不同进程中的计算方式(或不计算方式)。您正在将所有进程的标记值初始化为

int tag = 1; 

及以后,对于进程级别 0,您将标记设置为

tag = a+b;

第一次设置时,会将 tag 设置为 0,因为 ab 都从零开始。但是,对于等级高于 0 的进程,标签永远不会更改。他们将继续将标签设置为 1。

标签唯一标识由MPI_IsendMPI_Irecv发送的消息,这意味着发送及其对应的接收必须具有相同的标签才能成功传输数据.由于大多数接收的进程之间的标签不匹配,因此传输大多不成功。这会导致等级高于 0 的进程最终永远阻塞(等待)对 MPI_Wait 的调用。

为了解决这个问题,您必须确保更改排名高于零的进程的标签。然而,在我们这样做之前,还有一些其他问题值得讨论。

按照您现在为 0 级进程设置标签的方式,tag 只能具有 0 到 4 的值(假设有 3 个进程)。这是因为 a 被限制在 0 到 3 的范围内,而 b 只能有值 0 或 1。这些值的最大可能总和是 4。这意味着当您使用 arr[tag][0] 访问您的数组时,您将错过很多数据,并且您将多次重新发送相同的行。我建议更改发送每个子数组(您当前正在使用 tag 访问)的方式,这样您只有一个 for 循环来确定要发送哪个子数组,而不是两个嵌入式循环。然后,您可以计算将数组发送到as的过程

dest = subarray_index%(world_size - 1) + 1;

这将在等级大于零的进程之间交替分配。您可以将标记保留为 subarray_index。在接收端,您需要计算每个进程、每个接收的标签。

最后,我看到您在发送数据后正在初始化数组。你想事先做到这一点。

结合所有这些方面,我们得到

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

int main (int argc, char *argv[])
{
        MPI_Init(&argc, &argv);
        int world_rank;
        MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
        int world_size;
        MPI_Comm_size(MPI_COMM_WORLD, &world_size);        
        int tag = 1;        
        int arr[8][10]; 
        MPI_Request request;
        MPI_Status status;
        int source = 0;
        int dest;

        printf ("\n--Current Rank: %d\n", world_rank);

        if (world_rank == 0)
        {
            int i = 0;
            int a, b, x, y;

            printf("* Rank 0 excecuting\n");
            //I've moved the array generation to before the sends.
            for(x=0; x<8; x++)//Generating the whole 8 by 10 2D array
            {   
                i++;
                for ( y = 0; y < 10; y++ )
                {
                    arr[x][y] = i; 
                }   
            }

            //I added a subarray_index as mentioned above.
            int subarray_index;
            for(subarray_index=0; subarray_index < 8; subarray_index++)
            {
                dest = subarray_index%(world_size - 1) + 1;     
                tag = subarray_index;
                MPI_Isend(&arr[subarray_index][0], 10, MPI_INT, dest, tag, MPI_COMM_WORLD, &request);
            }

        }
        else 
        {
            int a, b;                   
            for(b=0; b<8/(world_size-1); b++)
            {
                int sum = 0;
                int i;
                //We have to do extra calculations here. These match tag, dest, and subarray.
                int my_offset = world_rank-1;
                tag = b*(world_size-1) + my_offset;
                int subarray = b;
                MPI_Irecv(&arr[subarray][0], 10, MPI_INT, source, tag, MPI_COMM_WORLD, &request);
                MPI_Wait (&request, &status);               
                for(i = 0; i<10; i++)
                {   
                    sum = arr[subarray][i]+sum;
                }
                printf("\nSum is: %d at rank: %d and tag is:%d\n", sum, world_rank, tag);
            }           
        }
        MPI_Finalize();
}

在这个版本中有一件事似乎还没有完成,您需要考虑:如果您的进程数发生变化,会发生什么情况?例如,如果您有 4 个进程而不是 3 个,看起来您可能会遇到循环问题

for(b=0; b<8/(world_size-1); b++)

因为每个进程将执行相同的次数,但发送的数据量并没有完全分配给 3 个工作进程(非零秩进程)。

但是,如果这不是您关心的问题,那么您就不需要处理此类情况。

关于c - 如何在MPI中传递二维数组并使用C语言创建动态标签值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32660848/

相关文章:

python - 并行执行函数列表

c - 哪些用户可以使用 setpgid() 函数?

c - 为什么我的双指针为空?

python - 在 python : child processes going defunct while others are not, 中不确定为什么

java - 使用多线程并行化 Java 中的 for 循环

linux - 在 Linux 中使用 mpirun 时出现错误 “ssh: Name or service not known”

python - 在Python中使用ctypes将指针传递给结构指针到C函数

c - 我怎么知道进程在哪个核心上运行?

c++ - 应用程序缓冲区和系统缓冲区有什么区别

c++ - MPI_测试 : MPI_ERR_TRUNCATE