并行计算MPI(入门)——点对点通信


如上次所述,有两种类型的通信,一种是点对点通信(从现在起我们称之为 P2P),另一种是集体通信。 P2P 通信分为两种操作:发送(Send)和接收(Receive): 发送和接收。

最基本的 P2P 通信形式称为阻塞通信。 发送信息的进程会一直等待,直到接收进程接收完所有信息。 这是最简单的通信方式,但不一定是最快的,我们将在下面的课程中看到这一点。

一、发送信息

发送操作是向另一个进程发送某一类型的数据缓冲区。 P2P 消息具有以下属性

  1. 数据地址的引用
  2. 数据类型
  3. 数据数量
  4. 数据标签
  5. 目的地标识
  6. 通信器

让我们逐一介绍每一个元素,并详细说明它们是什么。

1.1数据地址的引用

引用始终是指向缓冲区的指针。 该数组将保存希望从当前进程发送到另一进程的数据。

1.2数据类型

数据类型必须与缓冲区中存储的数据精确对应。 为此,MPI 提供了可使用的预定义类型。 最常见的类型及其对应的 C 语言类型是 :

C TypeMPI Type
charMPI_CHAR
intMPI_INT
floatMPI_FLOAT
doubleMPI_DOUBLE

还有很多其他类型,您可以在官方 MPI 标准文档中找到。 您也可以创建自己的数据类型。

1.3数据数量

这一项不言自明。 缓冲区中要发送到目的地的元素数量。

1.4数据标签

标签是一个简单的整数,用于识别通信的 “类型”。 这是一个完全非正式的值,由您自己设定。

1.5目的地标识

要发送数据的进程的rank

1.6通信器

向哪个通讯器发送数据。 请记住,进程的级别可能会根据您选择的通讯器而改变。

二、接收信息

接收信息的方式与发送操作完全相同。 不过,调用时需要的不是目的地 id,而是源 id:即正在等待消息的进程的标识。 此外,根据您使用的是阻塞通信还是非阻塞通信,您还需要额外的参数,但我们会在适当的时间和地点介绍这些参数。 现在让我们来亲身体验一下。

三、实例

练习的目的如下: 程序将在两个进程中运行。 您的程序将从命令行中随机获得两个整数,并读入变量 local_value。 然后,根据进程的 id,你的程序会有不同的行为:

Process #0

  1. 将整数发送至 Process #1
  2. 接收Process #1的整数
  3. 将两个值的总和写入 sum

Process #1

  1. 接收Process #0 的整数
  2. 将整数发送至 Process #0
  3. 将两个值的乘积写入 product

注意这两个进程的前两个操作的顺序是颠倒的,这样我们就可以避免阻塞通信中最常见的问题之一:死锁。

3.1 发送信息代码

您可以使用 MPI_Send 命令向进程发送信息:

int MPI_Send(void *buf, int count , MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)

简单说明一下这几个参数:

  1. void *buf:提供发送信息的指针
  2. int count:发送信息的数目
  3. MPI_Datatype datatype:发送信息的数据类型
  4. int dest:发送信息的进程(rank
  5. int tag:数据标签
  6. MPI_Comm comm:发送通信器

给几个简单的发送例子:

  1. 向进程 2 发送一个整数 :
int my_val = 10;
MPI_Send(&my_val, 1, MPI_INT, 2, 0, MPI_COMM_WORLD);
  1. 向进程 1 发送整数表:
int values[5] = {1, 2, 3, 4, 5};
MPI_Send(values, 5, MPI_INT, 1, 0, MPI_COMM_WORLD);
  1. 向处理 10 发送带有特定标记 6 的双精度表:
double values[3] = {1e25, -0.0, M_PI};
MPI_send(values, 3, MPI_DOUBLE, 10, 6, MPI_COMM_WORLD);

3.2 接收信息代码

从进程接收数据所调用的函数与发送数据的函数非常相似,但多了一个参数:

int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status);

正如你所看到的,还有一个额外的状态参数。 我们暂且忽略它,将其值设为MPI_STATUS_IGNORE,在下一个练习中我们会看到更多关于它的信息。

除了常规参数外,还有两个通配符可以使用。 MPI_ANY_SOURCE(MPI_ANY_SOURCE)而不是一个精确的报文来源 ID,表示可以接收来自任何来源的报文。 MPI_ANY_TAG 意义相同,但适用于任何标记。

最后,"计数 "参数表示在通信中预计收到的元素的最大数量。 因此,实际收到的元素数量可以少于或等于此数。 如果收到的元素较多,则会触发错误。

现在我们来看几个调用 MPI_Recv 的示例:

  1. 从进程 5 接收一个标记为 0 的整数:
int value;
MPI_Recv(&value, 1, MPI_INT, 5, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
  1. 从流程 3 收到一个包含 10 个整数的表,没有标记:
int values[10];
MPI_Recv(&values, 10, MPI_INT, 3, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
  1. 接收来自任何程序的 3 个加倍表,并带有任何标记 :
double values[3];
MPI_Recv(&values, 3, MPI_DOUBLE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE);

3.3 完整代码

#include <iostream>
#include <mpi.h>
#include <cstdlib>
using namespace std;

int main(int argc, char** argv) {
    MPI_Init(&argc, &argv);

    int rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    // Read the local value of the process
    // local_value will hold a specific int for process 0, and another for process 1
    int local_value=1;
    //local_value = atoi(argv[1]);//atoi将字符串数字转化为整数

    int other_value;
    if (rank == 0) {
        // Here, enter the code for the first process :
        // 1- Send the value to process 1 
        // 2- Receive the value from process 1 (in other_value)
        // 3- Print the sum of the two values on stdout 
        MPI_Send(&local_value, 1, MPI_INT, 1, 0, MPI_COMM_WORLD);
        MPI_Recv(&other_value, 1, MPI_INT, 1, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
        int sum = local_value + other_value;
        cout << local_value<< "," << other_value<<"," << sum << endl;
    }
    else {
        // Here enter the code for the second process :
        // 1- Receive the value from process 0 (in other_value)
        // 2- Send the value to process 0
        // 3- Print the product of the two values on stdout
        MPI_Recv(&local_value, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
        other_value = 2;
        MPI_Send(&other_value, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
        int product = local_value * other_value;
        cout << local_value <<"," << other_value <<"," << product << endl;
    }

    MPI_Finalize();

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值