• MPI学习笔记(一):初识MPI


    参考自:https://www.cnblogs.com/hantan2008/p/5452353.html#3697454

    1. 安装:

    Ubuntu 里似乎很简单

    sudo apt-get install mpich

    2. 编写 mpi 程序

    #include<iostream>
    using namespace std;
    #include"mpi.h"
    #include<cmath>
    
    int main(int argc, char ** argv){
    
        int myid, numprocs;
        int namelen;
        char processor_name [ MPI_MAX_PROCESSOR_NAME ];
    
        MPI_Init( &argc, &argv);
        MPI_Comm_rank( MPI_COMM_WORLD, & myid);
        MPI_Comm_size( MPI_COMM_WORLD, & numprocs);
        MPI_Get_processor_name( processor_name, & namelen);
    
        fprintf( stderr, "Hello World! Process %d of %d on %s 
    ", myid, numprocs, processor_name);
        MPI_Finalize();
    
        cout<<" argc = "<<argc<<endl;
        int n=0;
        for(int i=0;i<argc;i++){
            cout<<"i="<<i<<" argv[i] = "<<argv[i]<<endl;
        }
        return 0;
    }

    需要包含 "mpi.h"

    其中,MPI_Init( int * argc_p, char *** argv_p ) 是初始化函数,叫电脑知道,做好 mpi 相关的初始化。传入的 argc_p, argv_p 是指向 main 函数的命令行参数 argc, argv 的指针。如果没有命令行参数,也可以输入 NULL。

    MPI_COMM_WORLD:通讯子,“一组可以互发消息的进程集合”

    int MPI_Comm_rank( __in MPI_Comm comm, __out int * rank ) :第一个参数是输入参数——通信子,第二个参数是输出参数——进程号。

    int MPI_Comm_size( __in MPI_Comm comm, __out int * size ):第一个参数是输入参数——通信子,第二个参数是输出参数——通信子中总进程数。

    MPI_MAX_PROCESSOR_NAME:似乎是一个整数,值为128.

    MPI_Get_processor_name( ..):得到处理器的名字

    int MPI_Send (void *buf, int count, MPI_Datatype datatype,int dest, int tag,MPI_Comm comm):点对点发送消息。

        *buf: 发送缓冲区,指向发送的变量地址

        count: 发送的数据个数

        datatype:发送的数据类型

        dest: 目标进程序号,取值为 0 到 np-1 的整数

        tag: 消息标签,取值为 0  到 MPI_TAG_UB

        comm:通信器
    int MPI_Recv (void *buf, int count, MPI_Datatype datatype,int source, int tag, MPI_Comm comm,MPI_Status *status):点对点接收消息。

        与 MPI_Send 相似,不同的是 MPI_Status * status 为接收状态。MPI_Status 似乎是 MPI 自己定义的一个类,估计手册上有。

    3. 编译 mpi 并行程序

    mpicxx main.cpp
    

     4. 运行 mpi 并行程序

    mpirun -np 2 ./a.out

    其中,np 表示进程数。

    得到结果为

    Hello World! Processor 0 of 2 on DESKTOP_1IJIBGL
    Hello World! Processor 0 of 2 on DESKTOP_1IJIBGL
     argc = 1
    i=0 argv[i] = ./a.out
     argc = 1
    i=0 argv[i] = ./a.out

    令我不解的是,代码中 MPI_Finilize(); 后面的内容也被执行了两遍。

    5. 点对点通信

    #include<iostream>
    using namespace std;
    #include"mpi.h"
    #include<cmath>
    
    int main(int argc, char ** argv){
    
        int myid, numprocs;
        int namelen;
        char processor_name [ MPI_MAX_PROCESSOR_NAME ];
        int ha;
        int i;
        int total = 0;
    
        MPI_Init( &argc, &argv);
        MPI_Comm_rank( MPI_COMM_WORLD, & myid);
        MPI_Comm_size( MPI_COMM_WORLD, & numprocs);
    
    
        if( myid !=0 ){
            ha = myid;
            MPI_Send( &ha, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
        }
        else{
            for( i = 1; i < numprocs; i++){
                MPI_Recv( &ha, 1, MPI_INT, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
                total += ha;
            }
            cout<< " total = "<<total<<endl;
        }
    
        MPI_Finalize();
    
        return 0;
    }

    编译上面的文件以后,运行

    mpirun -np n ./a.out

    则会得到 n(n-1)/2

    进程 1,2,..., np-1 会向进程 0 发送 其序号的值,而进程 0 将收到的这些值全部加起来。

    6. 集体通信 (collective communications)

    包括各种 点对多,多对点,多对多,可参考第一排的链接,或者官网上的 documentation,我还没搞到一本比较全的 documentation。

    这里先试用一下 int MPI_Reduce (void *sendbuf, void *recvbuf, int count,MPI_Datatype datatype, MPI_Op op, int root,MPI_Comm comm)

    op 可以是 MPI_MAX, MPI_MIN, MPI_SUM, MPI_PROD 等等。root 为根进程的序号。

    #include<iostream>
    using namespace std;
    #include"mpi.h"
    #include<cmath>
    
    int main(int argc, char ** argv){
    
        int myid, numprocs;
        int namelen;
        char processor_name [ MPI_MAX_PROCESSOR_NAME ];
        int ha;
        int i;
        int total = 0;
    
        MPI_Init( &argc, &argv);
        MPI_Comm_rank( MPI_COMM_WORLD, & myid);
        MPI_Comm_size( MPI_COMM_WORLD, & numprocs);
    
        MPI_Reduce( & myid, & total, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD );
    
        if( myid ==0 ){
            cout<<" total = "<<total<<endl;
        }
    
        MPI_Finalize();
    
        return 0;
    }

    和之前的程序功能一样,都是计算 n(n-1)/2,但是一行就搞定了。

  • 相关阅读:
    Atitit 华为基本法 attilax读后感
    Atitit 华为管理者内训书系 以奋斗者为本 华为公司人力资源管理纲要 attilax读后感
    Atitit 项目版本管理gitflow 与 Forking的对比与使用
    Atitit 管理的模式扁平化管理 金字塔 直线型管理 垂直管理 水平管理 矩阵式管理 网状式样管理 多头管理 双头管理
    Atitit 乌合之众读后感attilax总结 与读后感结构规范总结
    深入理解 JavaScript 异步系列(4)—— Generator
    深入理解 JavaScript 异步系列(3)—— ES6 中的 Promise
    深入理解 JavaScript 异步系列(2)—— jquery的解决方案
    深入理解 JavaScript 异步系列(1)——基础
    使用 github + jekyll 搭建个人博客
  • 原文地址:https://www.cnblogs.com/luyi07/p/10820735.html
Copyright © 2020-2023  润新知