MPI中的Bcast, Reduce和Gather使用举例

来源:互联网 发布:ubuntu etcd集群搭建 编辑:程序博客网 时间:2024/05/17 23:39

欢迎关注白马负金羁的博客 http://blog.csdn.net/baimafujinji,为保证公式、图表得以正确显示,强烈建议你从该地址上查看原版博文。本博客主要关注方向包括:数字图像处理、算法设计与分析、数据结构、机器学习、数据挖掘、统计分析方法、自然语言处理。


MPI_Gather

MPI中的Gather用于从不同节点中收集一个等长的序列(数组)到一个指定的节点中(一个同类型的数组中)。
Instead of spreading elements from one process to many processes, MPI_Gather takes elements from many processes and gathers them to one single process. MPI_Gather的函数原型如下:

MPI_Gather(    void* send_data,    int send_count,    MPI_Datatype send_datatype,    void* recv_data,    int recv_count,    MPI_Datatype recv_datatype,    int root,    MPI_Comm communicator)

下面来看一个实例程序:

//author: http://blog.csdn.net/baimafujinji/#include <iostream>#include <cstdlib>#include "mpi.h"#define N 4using namespace std;int main(int argc, char * argv[]) {    int size, rank;    MPI_Init(&argc,&argv);    MPI_Datatype rtype;    MPI_Comm_size(MPI_COMM_WORLD, &size);    MPI_Comm_rank(MPI_COMM_WORLD, &rank);    double *collection;    collection = (double*)malloc(sizeof(double)*size*N);    double path_pack[N] = {1.0,1.0,1.0,1.0};    for(int i = 0; i < N; i++)        path_pack[i] += (double)rank;    if(rank == 0){        for (int j = 0; j < N; j++)        {            cout<<path_pack[j]<<" ";        }        cout<<endl;    }    if(rank == 1){        for (int j = 0; j < N; j++)        {            cout<<path_pack[j]<<" ";        }        cout<<endl;    }    if(rank == 2){    for (int j = 0; j < N; j++)        {            cout<<path_pack[j]<<" ";        }        cout<<endl;    }    MPI_Type_contiguous( N, MPI_DOUBLE, &rtype );    MPI_Type_commit( &rtype );    MPI_Gather(path_pack, N, MPI_DOUBLE, collection, 1, rtype, 0, MPI_COMM_WORLD);    MPI_Barrier(MPI_COMM_WORLD);    if(rank == 0){        for(int i = 0; i<size; i++)        {            for (int j = 0; j < N; j++)            {                cout<<collection[i*N+j]<<" ";            }            cout<<endl;        }    }    free(collection);    MPI_Finalize();}

上述代码的执行结果如下:

$ mpirun -n 3 ./a.out2 2 2 2 1 1 1 1 3 3 3 3 1 1 1 1 2 2 2 2 3 3 3 3

注意上述结果中由于三个节点是并行执行的,所以程序输出的头三行内容顺序是可变的,后三行这是按顺序统一收回后输出的,内容是不会变动的。需要注意的是,Gather一个2D array目前在MPI中还不能做到,也就是说如果上述d代码中的collection变成int**,这程序是会执行异常的,所以只能采用上面的方法将其转换为1D array再行处理。


MPI_Bcast与MPI_Reduce

下面这个例子演示了MPI中Bcast和Reduce的使用。更具体地,我们不仅广播一个矩阵到所有有节点,我们还广播矩阵中的某一行,最后我们Reduce一个矩阵。

//author: http://blog.csdn.net/baimafujinji/#include <cstdio>#include <cstring>#include "mpi.h"#define MAX 4int matrix[MAX][MAX];int result[MAX][MAX];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);    memset(matrix, 0 , sizeof(matrix));    memset(result, -1, sizeof(result));    if(rank == 0){        for(int i = 0; i<MAX; i++){            for (int j = 0; j < MAX; j++)            {                printf("%d ", matrix[i][j]);            }            printf("\n");        }        printf("\n");    }    MPI_Bcast(matrix, MAX*MAX, MPI_INT, 0, MPI_COMM_WORLD);    for(int i = 0; i<MAX; i++)        matrix[rank][i]=rank;    MPI_Bcast(&matrix[2], MAX, MPI_INT, 2, MPI_COMM_WORLD);    if(rank == 1){    printf("rank = %d\n", rank);        for(int i = 0; i<MAX; i++)            matrix[rank][i]=-1;        for(int i = 0; i<MAX; i++){            for (int j = 0; j < MAX; j++)            {                printf("%d ", matrix[i][j]);            }            printf("\n");        }        printf("\n");    }    if(rank == 2){    printf("rank = %d\n", rank);        for(int i = 0; i<MAX; i++){            for (int j = 0; j < MAX; j++)            {                printf("%d ", matrix[i][j]);            }            printf("\n");        }        printf("\n");    }    MPI_Reduce(matrix, result, MAX*MAX, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);    if(rank == 0){        for(int i = 0; i<MAX; i++){            for (int j = 0; j < MAX; j++)            {                printf("%d ", result[i][j]);            }            printf("\n");        }        printf("\n");    }    MPI_Finalize();    return 0;}

执行上述程序,所得之结果如下:

$ mpirun -n 4 ./atest.out0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 rank = 20 0 0 0 0 0 0 0 2 2 2 2 0 0 0 0 rank = 10 0 0 0 -1 -1 -1 -1 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 3 3 3 3 

需要注意的是,下面这种写法是错误的,rank所在位置的参数必须是一个确切的数值。

MPI_Bcast(&matrix[rank], MAX, MPI_INT, rank, MPI_COMM_WORLD);

所以如果你写成下面这样的程序:

//author: http://blog.csdn.net/baimafujinji/#include <cstdio>#include <cstring>#include "mpi.h"#define MAX 4int matrix[MAX][MAX];int result[MAX][MAX];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);    memset(matrix, 0 , sizeof(matrix));    memset(result, -1, sizeof(result));    if(rank == 0){        for(int i = 0; i<MAX; i++){            for (int j = 0; j < MAX; j++)            {                printf("%d ", matrix[i][j]);            }            printf("\n");        }        printf("\n");    }    MPI_Bcast(matrix, MAX*MAX, MPI_INT, 0, MPI_COMM_WORLD);    for(int i = 0; i<MAX; i++)        matrix[rank][i]=rank;    MPI_Bcast(&matrix[rank], MAX, MPI_INT, rank, MPI_COMM_WORLD);    if(rank == 2){        for(int i = 0; i<MAX; i++){            for (int j = 0; j < MAX; j++)            {                printf("%d ", matrix[i][j]);            }            printf("\n");        }        printf("\n");    }    MPI_Reduce(matrix, result, MAX*MAX, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);    if(rank == 0){        for(int i = 0; i<MAX; i++){            for (int j = 0; j < MAX; j++)            {                printf("%d ", result[i][j]);            }            printf("\n");        }        printf("\n");    }    MPI_Finalize();    return 0;}

执行上述代码之结果如下:

$ mpirun -n 4 ./atest.out0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 2 0 0 0 0 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3 

可见上代码中广播某一行的代码没有起到任何作用!这一点在实际开发中应该予以小心。


参考文献与推荐阅读材料

【1】http://mpitutorial.com/tutorials/mpi-scatter-gather-and-allgather/

4 0