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

原文地址:https://www.cnblogs.com/luyi07/p/10820735.html