• 【转】MPI入门


    author: Menglong TAN; email: tanmenglong_at_gmail; twitter/weibo: @crackcell; source:http://blog.crackcell.com/posts/2013/07/15/mpi_quick_start.html.

    1 前言

      不知道为啥,MPI的入门教程似乎很少,也不太明了。今天看了一些教程,整理一下入门需要知道的知识点。

    2 开发环境设置

      环境:debian sid 安装开发环境:

    $ sudo apt-get install openmpi-bin openmpi-doc libopenmpi-dev gcc g++

    3 Learn by example

     

    3.1 例子1:Hello world

    #include <iostream>
    #include <mpi/mpi.h>
    
    using namespace std;
    
    int main(int argv, char* argc[]){
        MPI_Init(&argv, &argc);
        cout << "hello world" << endl;
        MPI_Finalize();
        return 0;
    }
    

    编译:

    $ mpicxx -o hello.exe hello.cpp

    运行:

    $ mpirun -np 10 ./hello.exe

    • -np 10 参数制定了运行了程序的10个拷贝

    3.2 代码结构

       我们来看代码,MPI程序的结构一般是:

    1. 头文件、全局定义
    2. 初始化MPI环境:MPI_Init()
    3. 分布式代码
    4. 终止MPI环境:MPI_Finalize()
    5. 结束

    3.3 一些基本的API

     

    3.3.1 初始化环境:MPI_Init

    #include <mpi.h>
    int MPI_Init(int *argc, char ***argv)
    

    3.3.2 是否初始化:MPI_Initialized

    #include <mpi.h>
    int MPI_Initialized(int *flag)
    

    3.3.3 终止环境:MPI_Finalize

    #include <mpi.h>
    int MPI_Finalize()
    

    3.3.4 获取进程数:MPI_Comm_size

    获取一个communicator中的进程数

    #include <mpi.h>
    int MPI_Comm_size(MPI_Comm comm, int *size)
    

    如果communicator是MPI_COMM_WORLD,那就是当前程序能用的所有进程数

    3.3.5 获取当前进程id:MPI_Comm_rank

    #include <mpi.h>
    int MPI_Comm_rank(MPI_Comm comm, int *rank)
    

    3.3.6 获取程序运行的主机名:MPI_Get_processor_name

    #include <mpi.h>
    int MPI_Get_processor_name(char *name, int *resultlen)
    

    3.3.7 终止一个communicator的所有进程:MPI_Abort

    #include <mpi.h>
    int MPI_Abort(MPI_Comm comm, int errorcode)
    

    3.4 例2:稍微复杂一点

    #include <stdio.h>
    #include <mpi/mpi.h>
    
    int main(int argc, char *argv[]) {
        char hostname[MPI_MAX_PROCESSOR_NAME];
        int task_count;
        int rank;
        int len;
        int ret;
    
        ret = MPI_Init(&argc, &argv);
        if (MPI_SUCCESS != ret) {
            printf("start mpi fail
    ");
            MPI_Abort(MPI_COMM_WORLD, ret);
        }
    
        MPI_Comm_size(MPI_COMM_WORLD, &task_count);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
        MPI_Get_processor_name(hostname, &len);
    
        printf("task_count = %d, my rank = %d on %s
    ", task_count, rank, hostname);
    
        MPI_Finalize();
    
        return 0;
    }
    

    运行一下:

    $ mpirun -np 3 ./hello3.exe task_count = 3, my rank = 0 on crackcell-vm0 task_count = 3, my rank = 1 on crackcell-vm0 task_count = 3, my rank = 2 on crackcell-vm0

    3.5 基本通信API

    • MPI提供了消息的缓存机制
    • 消息可以以阻塞或非阻塞的方式发送
    • 顺序性:MPI保证接收者收到消息的顺序和发送者的发送顺序一致
    • 公平性:MPI不保证调度公平性,程序员自己去防止进程饥饿

    3.5.1 消息数据类型

        为了可移植性,MPI定义了自己的消息数据类型,具体参考1

    3.5.2 点对点通信API

    • 阻塞发送:MPI_Send
      int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest,
                   int tag, MPI_Comm comm)
      
    • 非阻塞发送:MPI_Isend
      int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest,
                   int tag, MPI_Comm comm)
      
    • 阻塞接收:MPI_Recv
      int MPI_Recv(void *buf, int count, MPI_Datatype datatype,
                   int source, int tag, MPI_Comm comm, MPI_Status *status)
      
    • 非阻塞接收:MPI_Irecv
      int MPI_Irecv(void *buf, int count, MPI_Datatype datatype,
                    int source, int tag, MPI_Comm comm, MPI_Request *request)
      

    3.6 例3:阻塞的消息传递

    #include <stdio.h>
    #include <mpi/mpi.h>
    
    int main(int argc, char *argv[]) {
        int task_count;
        int rank;
        int dest;
        int src;
        int count;
        int tag = 1;
    
        char in_msg;
        char out_msg = 'x';
    
        MPI_Status status;
    
        MPI_Init(&argc, &argv);
        MPI_Comm_size(MPI_COMM_WORLD, &task_count);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    
        if (0 == rank) {
            dest = 1;
            src = 1;
            // 向1发送一个字符,然后等待返回
            MPI_Send(&out_msg, 1, MPI_CHAR, dest, tag, MPI_COMM_WORLD);
            MPI_Recv(&in_msg, 1, MPI_CHAR, src, tag, MPI_COMM_WORLD, &status);
        } else if (1 == rank) {
            dest = 0;
            src = 0;
            // 向0发送一个字符,然后等待返回
            MPI_Recv(&in_msg, 1, MPI_CHAR, src, tag, MPI_COMM_WORLD, &status);
            MPI_Send(&out_msg, 1, MPI_CHAR, dest, tag, MPI_COMM_WORLD);
        }
    
        MPI_Get_count(&status, MPI_CHAR, &count);
        printf("task %d: recv %d char(s) from task %d with tag %d
    ",
               rank, count, status.MPI_SOURCE, status.MPI_TAG);
    
        MPI_Finalize();
    
        return 0;
    }
    

    3.7 协同通信API

    • 协同通信必须涉及同一个communicator中的所有进程
    • 协同通信操作的类型
      1. 同步操作:进程等待同组的其它成员到达某一同步点
      2. 数据移动操作:broadcast、scatter/gather操作
      3. 协同计算:某个成员收集其它成员的数据,然后执行某个操作

    3.7.1 阻塞直到同组其它任务完成:MPI_Barrier

    #include <mpi.h>
    int MPI_Barrier(MPI_Comm comm)
    

    3.7.2 Broadcast消息:MPI_Bcast

    #include <mpi.h>
    int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype,
                  int root, MPI_Comm comm)
    

    3.7.3 散播消息:MPI_Scatter

    #include <mpi.h>
    int MPI_Scatter(void *sendbuf, int sendcount, MPI_Datatype sendtype,
                    void *recvbuf, int recvcount, MPI_Datatype recvtype, int root,
                    MPI_Comm comm)
    

    3.7.4 收集消息:MPI_Gather

    #include <mpi.h>
    int MPI_Gather(void *sendbuf, int sendcount, MPI_Datatype sendtype,
                   void *recvbuf, int recvcount, MPI_Datatype recvtype, int root,
                   MPI_Comm comm)
    

    更多API参考2

    3.8 组和通信器

    • 一堆有序的进程组成一个group,每个进程有一个唯一的整数标识
    • 一个communicator组织起了一堆需要相互之间通信的进程。MPI_COMM_WORLD包含了所有进程

    group用来组织一组进程,communicator用来关联他们之前的通信关系。

    Date: Mon Jul 15 11:55:20 2013

    Author: Tan Menglong

    Org version 7.9.3f with Emacs version 24

    Validate XHTML 1.0

  • 相关阅读:
    MinIO:入门
    JS中面向对象的多种继承方式
    点击按钮实现图片下载
    给大家推荐一个免费的云平台-阿贝云
    REPLACE
    SUBSTRING_REGEXPR 截取字符串
    基本的git/linux/g++/ 等指令
    C++引用和指针&, *
    go语言异常处理 error panic recover defer
    django.db.utils.IntegrityError: (1048, "Column 'id' cannot be null")
  • 原文地址:https://www.cnblogs.com/gkwang/p/4337679.html
Copyright © 2020-2023  润新知