【问题标题】:Adding an array using MPI in C language在 C 语言中使用 MPI 添加数组
【发布时间】:2015-09-13 23:22:22
【问题描述】:

我对 MPI 编程非常陌生。在下面的代码中,我尝试使用进程 1 添加前 3 个元素,使用进程 2 添加后 3 个元素。结果应该显示前三个元素的 Sum is 11 和后三个元素的 Sum is 18。我看到我的问题的原因是在等级 2(进程 2)它读取 arr[3] 作为数组的第一个元素。我真的很迷茫为什么它没有正确读取第 2 级的数组的第三个元素

#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 tag2 = 1;
        int tag1 = 2;       
        int arr[7] = { 6,2,3,9,4,5};

        printf ("\n--Current Rank: %d\n", world_rank);
        int index;
        int source = 0;
        int dest;
        if (world_rank == 0)
        {
            printf("* Rank 0 excecuting");
            index = 0;
            dest = 1;
            MPI_Send(&index, 1, MPI_INT, dest, tag1, MPI_COMM_WORLD);
            MPI_Send(&arr, 2, MPI_INT, dest, tag2, MPI_COMM_WORLD); 

            index = 3;
            dest = 2;
            MPI_Send(&index, 1, MPI_INT, dest, tag1, MPI_COMM_WORLD);
            MPI_Send(&arr, 1, MPI_INT, dest, tag2, MPI_COMM_WORLD);
        }
        else 
        {
            int sum = 0;
            int i;
            MPI_Recv(&index, 1, MPI_INT, source, tag1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
            MPI_Recv(&arr[index], 20, MPI_INT, source, tag2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
            printf("At Rank: %d index is: %d\n", world_rank, index);
            for(i = index; i<=index+2; i++)
            {   
                printf("i: %d and arr[i]: %d\n", i, arr[i]);
                sum = arr[i]+sum;
            }
            printf("\n Sum is: %d and arr[3]: %d\n", sum, arr[3]);
        }       

        MPI_Finalize();
}

使用命令后得到的结果:mpirun -np 3 test1

--Current Rank: 0

--Current Rank: 1
At Rank: 1 index is: 0
i: 0 and arr[i]: 6
i: 1 and arr[i]: 2
i: 2 and arr[i]: 3

 Sum is: 11 and arr[3]: 9 //here it shows the correct value of 3rd array element

--Current Rank: 2
At Rank: 2 index is: 3
i: 3 and arr[i]: 6 //Error happens here
i: 4 and arr[i]: 4
i: 5 and arr[i]: 5

 Sum is: 15 and arr[3]: 6 //Show the wrong array value for 3rd element
* Rank 0 excecuting

【问题讨论】:

    标签: c parallel-processing mpi


    【解决方案1】:

    嗯,代码按你说的做......

            index = 3;
            dest = 2;
            MPI_Send(&index, 1, MPI_INT, dest, tag1, MPI_COMM_WORLD);
            MPI_Send(&arr, 1, MPI_INT, dest, tag2, MPI_COMM_WORLD);
    

    也许你想要更多:

            index = 3;
            dest = 2;
            MPI_Send(&index, 1, MPI_INT, dest, tag1, MPI_COMM_WORLD);
            MPI_Send(&arr[index], 3, MPI_INT, dest, tag2, MPI_COMM_WORLD);
    

    而其他索引“有效”的事实是因为初始分配......

    这段代码还有一些问题:

    1. int arr[7] = { 6,2,3,9,4,5};: 可能是int arr[] = {6,2,3,9,4,5};

    2. MPI_Send(&amp;arr, 2, MPI_INT, dest, tag2, MPI_COMM_WORLD); 可能应该是 MPI_Send(&amp;arr[index], 3, MPI_INT, dest, tag2, MPI_COMM_WORLD);,尽管我不太确定您打算这样做。

    3. MPI_Recv(&amp;arr[index], 20, MPI_INT, source, tag2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);:这个20来自哪里?不应该是3吗?

    希望这对你有意义。

    【讨论】:

    • 非常感谢您通过示例和详细信息解释所有内容。你帮了大忙
    【解决方案2】:

    我是 MPI 的新手。但这就是我对 MPI 的了解。如果我错了,请纠正我。

    • 通常等级为 0 的进程接收来自其他进程的消息并打印结果,或者它会进行必要的计算(在这种情况下,将它接收到的两个值相加)

    • 所有其他进程完成各自的工作并将其发送到进程 0。

    • 在这种情况下不需要标签,因为这只涉及简单的计算。

    所以解决方案可以这样简化。

    #include "mpi.h"
    #include <stdio.h>
    #include <stdlib.h>
    
    int main (int argc, char *argv[]){
    
            int world_rank,world_size, i;
            MPI_Init(&argc, &argv);
            MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
            MPI_Comm_size(MPI_COMM_WORLD, &world_size);  
    
            int arr[6] = {6,2,3,9,4,5};
    
            printf ("Current Rank: %d\n", world_rank);
    
            int total = 0;
    
            if(world_rank != 0){//if the rank is not 0, calculate the partial sum
                int tempTotal = 0;
    
                for(i = 0; i < 3; i++){
                    tempTotal += arr[(world_rank -1)* 3 + i];
                }
    
                printf("* Rank %d sending value %d\n",world_rank, tempTotal);
                MPI_Send(&tempTotal, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);//send the partial sum to process 0
                printf("* Rank %d value sent\n", world_rank);
    
            }else{
                printf("RANK 0 receiving values:\n");
    
                int temp;
    
                for(i = 1; i < world_size; i++){
                    MPI_Recv(&temp, 1, MPI_INT, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);//receive partial sums from other processes
    
                    printf("Received value %d from rank %d\n", temp, i);
    
                    total += temp;//add the partial sum to total
                }
    
                printf("Sum of the array = %d\n", total);//after all partial sums arrive, print the total
            }       
            MPI_Finalize();
    }
    

    运行代码:

    mpicc mpi.c -o mpi
    mpirun -np 3 ./mpi
    

    希望这会有所帮助。

    【讨论】:

    • 抱歉,但我倾向于完全不同意您对 MPI 代码通常工作或应该工作的方式的看法......请参阅我的(恐怕冗长)回答 here
    • @Gilles:非常感谢您分享您的经验。我读了你的回答。这真的很有趣。正如我上面提到的,我是 MPI 的新手。那么如果主/从方式是错误的,对于这类问题你建议采用什么样的方式呢?
    • 哪种问题?这个具体的问题是什么样的?其实,在现实生活中,不会出现这样的问题吧?但更一般地说,正如我在帖子中所解释的,大多数时候,找到解决并行问题的正确方法是全局思考,了解需要完成哪些工作以及由谁完成。然后确保(尽可能),进程能够自己获取他们需要的数据(可能使用并行 IO),完成他们的工作(与其他进程协作)并并行发布他们的结果,所有这些都是在平等的基础上。
    • 我的意思是使用 2 个进程查找数组的总和这种问题。您是如何解决这个问题的?
    • 如果数组尚未分发,则尝试并行求和是没有意义的,因为传输数据将比在拥有数据的进程上执行更长的时间。如果数组已经分布,那么每个进程都会进行部分归约,然后根据需要结果的位置使用 MPI_Reduce 或 MPI_Allreduce 进行全局归约。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-29
    • 2021-06-22
    • 1970-01-01
    • 2021-12-17
    • 2016-02-23
    相关资源
    最近更新 更多