如何使用MPI_Reduce独立地对不同处理器组中的不同值求和

时间:2013-02-11 14:02:58

标签: sum mpi

我正在尝试将处理器分成组,然后添加每个组的总和 独立......但直到现在我才能正确找到结果。 一个简单的例子如下:

int main(int argc, char** argv) 
{
    int size, rank,i=0,localsum1=0,globalsum1=0,localsum2=0,globalsum2=0;

    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD,&size);
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);

    if(rank==0)
    {
    }
    else if(rank==1)
    {
        localsum1 += 5;
        MPI_Reduce(&localsum1,&globalsum1,2,MPI_INT,MPI_SUM,0,MPI_COMM_WORLD);
    }
    else if(rank==2)
    {
        localsum2 += 10;
        MPI_Reduce(&localsum2,&globalsum2,2,MPI_INT,MPI_SUM,0,MPI_COMM_WORLD);
    }

    if(rank==0)
    {
        printf("globalsum1 = %d \n",globalsum1);
        printf("globalsum2 = %d \n",globalsum2);
    }
    MPI_Finalize();

    return (EXIT_SUCCESS);
}

我无法弄清楚这里缺少什么......有人可以帮忙吗?

1 个答案:

答案 0 :(得分:14)

MPI_Reducecollective operation。这意味着参与的通信器中的所有任务必须进行MPI_Reduce()呼叫。在上面,排名0从不调用MPI_Reduce()所以这个程序会挂起,因为其他一些处理器等待0级的参与永远不会来。

另外,因为它是整个通信器的集体操作,所以你需要做一些工作来划分减少。一种方法是减少一个int数组,并让每个处理器只贡献给它在数组中的元素:

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

int main(int argc, char** argv)
{
    int size, rank;

    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD,&size);
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);

    int localsum[2] = {0,0};
    int globalsum[2] = {0,0};

    if(rank % 2 == 1)
    {
        localsum[0] += 5;
    }
    else if( rank > 0 && (rank % 2 == 0))
    {
        localsum[1] += 10;
    }

    MPI_Reduce(localsum,globalsum,2,MPI_INT,MPI_SUM,0,MPI_COMM_WORLD);

    if(rank==0)
    {
        printf("globalsum1 = %d \n",globalsum[0]);
        printf("globalsum2 = %d \n",globalsum[1]);
    }

    MPI_Finalize();

    return (EXIT_SUCCESS);
}

现在正在运行

$ mpicc -o reduce reduce.c
$ mpirun -np 3 ./reduce
globalsum1 = 5 
globalsum2 = 10 

否则,您可以创建仅连接您希望参与每个总和的处理器的通信器,并在每个通信器中进行减少。下面是一个不太漂亮的方法。这通常非常强大,但比第一个解决方案更复杂:

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

int main(int argc, char** argv)
{
    int size, rank;

    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD,&size);
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);

    int localsum = 0;
    int globalsum = 0;

    MPI_Comm  comm_evens_plus_root, comm_odds_plus_root;
    MPI_Group grp_evens_plus_root, grp_odds_plus_root, grp_world;

    MPI_Comm_group(MPI_COMM_WORLD, &grp_world);
    int *ranks = malloc((size/2 + 1) * sizeof(rank));
    int i,j;
    for (i=1, j=0; i<size; i+=2, j+=1)
        ranks[j] = i;
    MPI_Group_excl(grp_world, j, ranks, &grp_evens_plus_root);
    MPI_Comm_create(MPI_COMM_WORLD, grp_evens_plus_root, &comm_evens_plus_root);

    for (i=2, j=0; i<size; i+=2, j+=1)
        ranks[j] = i;
    MPI_Group_excl(grp_world, j, ranks, &grp_odds_plus_root);
    MPI_Comm_create(MPI_COMM_WORLD, grp_odds_plus_root, &comm_odds_plus_root);

    free(ranks);

    if(rank % 2 == 1)
    {
        localsum += 5;
        MPI_Reduce(&localsum,&globalsum,1,MPI_INT,MPI_SUM,0,comm_odds_plus_root);
    }
    else if( rank > 0 && (rank % 2 == 0))
    {
        localsum += 10;
        MPI_Reduce(&localsum,&globalsum,1,MPI_INT,MPI_SUM,0,comm_evens_plus_root);
    }

    if(rank==0)
    {
        MPI_Reduce(&localsum,&globalsum,1,MPI_INT,MPI_SUM,0,comm_odds_plus_root);
        printf("globalsum1 = %d \n",globalsum);
        MPI_Reduce(&localsum,&globalsum,1,MPI_INT,MPI_SUM,0,comm_evens_plus_root);
        printf("globalsum2 = %d \n",globalsum);
    }

    MPI_Comm_free(&comm_odds_plus_root);
    MPI_Comm_free(&comm_evens_plus_root);
    MPI_Group_free(&grp_odds_plus_root);
    MPI_Group_free(&grp_evens_plus_root);
    MPI_Finalize();

    return (EXIT_SUCCESS);
}

跑步给出

$ mpicc -o reduce2 reduce2.c 
$ mpirun -np 3 ./reduce
globalsum1 = 5 
globalsum2 = 10