• 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,但是一行就搞定了。

  • 相关阅读:
    POJ-2387-Til the Cows Come Home 解题报告
    编程能力与编程年龄
    POJ-1703-Find them, Catch them 解题报告
    科学计算和可视化
    判断素数
    余初闻回文数,初试函数解,竟成!(指出前n个回文素数)
    经典题:*年*月*日是第几天
    验证码的校验
    天天向上的力量终于好了!!
    阶乘
  • 原文地址:https://www.cnblogs.com/luyi07/p/10820735.html
Copyright © 2020-2023  润新知