OpenMPI 学习笔记(五)通信模式

内容概要

  • Fonctions  功能
  • Communications bloquantes 阻塞式沟通
  • Envoi bloquant, mode bu􏰀fferisé  •阻塞发送,缓存模式
  • Envoi bloquant, mode synchrone •阻塞发送,同步模式
  • Envoi bloquant, mode ready  •阻塞发送,准备模式
  • Envoi bloquant, mode standard  •阻塞发送,标准模式
  • Communications non bloquantes  •非阻塞沟通模式

O- 功能

⚠️ 此图很重要,注意搭配使用! MPI_Recv 对应左边那一列,MPI_Irecv对应右边那一列

标准发送使用的模式由MPI在每个调用时​​决定。
MPI_Send,MPI_Bsend,MPI_Ssend,MPI_Rsend函数都具有相同的原型
MPI_Isend,MPI_Ibsend,MPI_Issend,MPI_Irsend函数都具有相同的原型

一、阻塞通信

当通讯存储空间(数据+信封)可以在释放后立即告诉下一个,而立即被重新使用时,这称为阻塞沟通。

就是说::::通信不会被阻塞,阻塞的是内存!!!!!

(用完以后及时告诉其他人“我用完了,你们快来用吧”)

??????
对于“重用”,意思是:
对于发送者,可以修改要发送的数据上的指针,并且可以释放指针本身而不影响通信(通常,MPI功能复制要传送的数据在临时缓存中),
对于接收器,指向要接收的数据的指针包含所有传输的数据,并且可以读取元素。 

 

发送者的阻塞(不幸是标准)感到困惑的地方:
该术语适用于包含要传输的数据的内存空间,而不适用于通信。
该术语并不意味着发件人等待通话结束才能退出MPI功能。
在数据传输开始之前,发送者甚至可以退出MPI功能。

接收这没有混淆:
当对阻塞接收的MPI功能的呼叫终止时,通信被有效终止

1. 阻塞-缓存模式 mode bu􏰀fferisé

以缓存模式发送时,信息和信封将被复制到发送过程的存储器中的其他位置。
相关函数:MPI_Bsend。
即使接收过程尚未处于等待消息的状态(它尚未到达接收方),也可以调用MPI_Bsend。
即使接受者尚未收到整个消息,或者尚未准备开始接收消息,对MPI_Bsend的调用也可终止。 
如果在调用MPI_Bsend发送时 接收者正在等待别的消息,则可以省略该buffer的消息(原来有别的在忙,先忽略这个消息,忙完别的再说)。

小结:因为此模式下,消息是存在缓存区的,不会直接到达接受者,不会要求接受者马上接收,所以接受者和发送者互不干扰。什么时候启用和停止MPI_Ssend都无所谓。

2. 阻塞发送-同步模式 mode synchrone

在同步模式下发送时,发送过程必须等待接收功能完成。
相关函数:MPI_Ssend。
即使接收过程尚未等待消息(尚未到达接收功能),也可以完成对MPI_Ssend的调用。(接受者没准备好,发送者也可以发MPI_Ssend)
这是同步两个进程的好方法。
在非阻塞接收的情况下(并且仅在这种情况下),接收功能以及对MPI_Ssend的调用可以在没有完全传送消息的情况下结束。(接收中断)

小结:此模式下,接受者没准备,发送者也能发送,但是发送者要等到接受者完全接受之后发送过程才能停止。

3. 阻塞发送-准备模式 mode ready

准备发送 仅在接收者已准备/等待 接收消息时才是正确的。
相关函数:MPI_Rsend。
可以省略某些通信操作,但是需要提前安排调度
接收过程不等待消息时 采用的行为是未确定的。
很少使用,因为非常危险。

4. 阻塞发送-标准模式 mode standard (根据情况选择)

标准模式的确切行为是在发送时决定的。
相关函数:MPI_Send。
根据数据的大小/进程的进度,MPI_Send将以MPI_Bsend,MPI_Ssend或MPI_Rsend的形式运行。
事先不可能确定他的行为。

二、 非阻塞通信

非阻塞调用 开始发送或接收消息后立即终止(程序继续执行)。
允许您在通讯过程中继续计算。
任何非阻塞呼叫都需要调用MPI_Wait函数(或其他同类函数)来正确完成调用。
在非阻塞发送的情况下,在调用MPI_Wait之前,包含该消息的内存不能被重用(但可以被读取)。
在非阻塞接收的情况下,在调用MPI_Wait之前,不能读取用于接收消息的内存。
非阻塞发送可以与阻塞接收配对,反之亦然

int MPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request);

int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request);

int MPI_Wait(MPI_Request *request, MPI_Status *status);
// non-bloquant.c

#include <mpi.h> 
#include <stdio.h>

int main(int argc, char** argv) {

    MPI_Init(NULL, NULL);
    int wrank;
    MPI_Comm_rank(MPI_COMM_WORLD, &wrank);

    int witness = 0; 
    MPI_Request request; 

    if (wrank==2)
    {
        int modifier = 1;
        MPI_Isend(&modifier, 1, MPI_INT, 3, 28, MPI_COMM_WORLD, &request);

        // Computations.
        MPI_Wait(&request, MPI_STATUS_IGNORE);
    }
    else if (wrank==3) 
    {
        MPI_Irecv(&witness, 1, MPI_INT, 2, 28, MPI_COMM_WORLD, &request);

        // Other computations.
        MPI_Wait(&request, MPI_STATUS_IGNORE);
    }

    printf("Rang %d, witness %d.\n", wrank, witness); 
    MPI_Finalize();
    return 0;
}
                          

$ mpirun -n 4 source

Rang 0, witness 0.  //无关进程

Rang 2, witness 0.  //发送者

Rang 3, witness 1.  //接受者

Rang 1, witness 0.  //无关进程

⚠️:每个非阻塞调用都需要一个MPI_Wait, request是非阻塞呼叫的身份标识

 

 

posted @ 2018-04-20 00:27  yanwenliqjl  阅读(2145)  评论(0编辑  收藏  举报