简单的 hello world 非阻塞 MPI [英] Simple hello world non blocking MPI

查看:55
本文介绍了简单的 hello world 非阻塞 MPI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在练习一个简单的非阻塞Hello world";本网站.

I am practicing a simple non-blocking "Hello world" program with this website.

#include <iostream>
#include <mpi.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
    MPI_Init(&argc, &argv);
    MPI_Request request;
    MPI_Status  status;

    int size, rank, data;

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    MPI_Comm_size(MPI_COMM_WORLD, &size);

    if (rank>0) {
    MPI_Irecv(&data, 1, MPI_INT, rank - 1, 0,  MPI_COMM_WORLD,&request);

      std::cout << "Rank " << rank << " has received message with data " << data<< " from rank " << rank - 1
              << std::endl;
    }

    std::cout << "Hello from rank " <<rank << " out of " << size<< std::endl;

    data=rank;

    MPI_Isend(&data, 1, MPI_INT, (rank + 1) % size, 0, MPI_COMM_WORLD, &request);

    MPI_Finalize();
    return 0;
}

我有几个问题:第一个是 (rank + 1) % size 对我来说没有意义.我希望这只是 rank+1 而不是 (rank + 1) % size.但是,当我删除 %size 时,代码不会运行.我的第二个歧义是这个特定代码的结果:

I have a couple of problems: the first one is (rank + 1) % size does not make sense to me. I expect this to be just rank+1 rahther than (rank + 1) % size. But, when I delete %size, the code doese not run. The second ambiguty I have is the result of this particular code which is :

#PTP job_id=12493
Rank 3 has received message with data 21848 from rank 2
Hello from rank 3 out of 4
Hello from rank 0 out of 4
Rank 2 has received message with data 22065 from rank 1
Hello from rank 2 out of 4
Rank 1 has received message with data 22043 from rank 0
Hello from rank 1 out of 4

我已将数据定义为等于排名,但它似乎抛出了一些随机的东西.这是为什么?

I have defined data to be equal to rank, but it seems it throws something random. Why is this?

推荐答案

TL;DR 代码中的主要问题(并且可能)数据显示随机值的原因是使用了 MPI_IrecvMPI_Isend 没有调用 MPI_Wait(或 MPI_Test).

TL;DR The main issue in your code (and likely) the reason data displays random values is the use of MPI_Irecv and MPI_Isend without the call of MPI_Wait (or MPI_Test).

MPI_IrecvMPI_Isend 是非阻塞通信例程,因此需要使用 MPI_Wait(或使用 MPI_Test 来测试请求是否完成)以确保消息完成,以及发送/接收缓冲区中的数据可以再次安全操作.

MPI_Irecv and MPI_Isend are nonblocking communication routines, therefore one needs to use the MPI_Wait (or use MPI_Test to test for the completion of the request) to ensure that the message is completed, and that the data in the send/receive buffer can be again safely manipulated.

假设您使用 MPI_Isend 发送一个整数数组而不调用 MPI_Wait;在这种情况下,您不确定何时可以安全地修改(或取消分配)该数组的内存.这同样适用于 MPI_Irecv.尽管如此,调用 MPI_Wait 可确保从那时起一种情况下读/写(或释放内存)缓冲区没有 未定义的行为 或不一致的数据.

Let us imagine that you send an array of ints using MPI_Isend without calling MPI_Wait; in such case you are not really sure when you can safely modify (or deallocate the memory of) that array. The same applies to MPI_Irecv. Nonetheless, calling MPI_Wait ensures that from that point onwards one case read/write (or deallocate the memory of) the buffer without risks of undefined behavior or inconsistent data.

MPI_Isend期间,必须读取和发送缓冲区的内容(例如整数数组);同样,在 MPI_Irecv 期间,接收缓冲区的内容必须到达.同时,可以将一些计算与正在进行的过程重叠,但是这种计算不能改变(或读取)发送/接收缓冲区的竞争.然后调用MPI_Wait 确保从那时起可以安全地读取/修改数据发送/接收,而不会出现任何问题.

During the MPI_Isend the content of the buffer (e.g., the array of ints) has to be read and sent; like-wise during the MPI_Irecv the content of the receiving buffer has to arrive. In the meantime, one can overlap some computation with the ongoing process, however this computation cannot change (or read) the contend of the send/recv buffer. Then one calls the MPI_Wait to ensure that from that point onwards the data send/recv can be safely read/modified without any issues.

在您的代码中,无论您如何调用:

In your code, however you call:

MPI_Irecv(&data, 1, MPI_INT, rank - 1, 0,  MPI_COMM_WORLD,&request);

之后不调用MPI_Wait.此外,您更改缓冲区的内容 data=rank;.如前所述,这会导致未定义的行为.

without calling MPI_Wait afterwards. Moreover, you change the content of the buffer i.e., data=rank;. As previously mention this can lead to undefined behavior.

您可以使用 MPI_RecvMPI_Send 代替或调用 MPI_IrecvMPI_Isend 后跟 MPI_Wait.在语义上调用 MPI_Isend() 然后调用 MPI_Wait() 或调用 MPI_Recv 然后调用 MPI_Wait() 与分别调用 MPI_Send()MPI_Recv() 相同.

You can fix this problem by either using MPI_Recv and MPI_Send instead or by calling MPI_Irecv and MPI_Isend followed by MPI_Wait. Semantically a call to MPI_Isend() followed by a call to MPI_Wait() or a call to MPI_Recv followed by MPI_Wait() is the same as calling MPI_Send() and MPI_Recv(), respectively.

我有几个问题:第一个是 (rank + 1) % size对我来说没有意义.我希望这只是排名 + 1 而不是(等级 + 1)% 大小.

I have a couple of problems: the first one is (rank + 1) % size does not make sense to me. I expect this to be just rank+1 rahther than (rank + 1) % size.

为了向您解释该表达式背后的原因,让我们考虑一下您的代码,其中包含 4 个进程,等级范围从 0 到 3.

To explain you the reasoning behind that expression let us think about your code with 4 processes, with ranks ranging from 0 to 3.

进程 1、2 和 3 将调用:

Process 1, 2 and 3 will call :

MPI_Irecv(&data, 1, MPI_INT, rank - 1, 0,  MPI_COMM_WORLD,&request);

  • 进程 1 期待来自进程 0 的消息;
  • 进程 2 期待来自进程 1 的消息;
  • 进程 3 需要一个消息表单进程 2;
  • 然后所有四个进程都调用(让我们相应地替换公式 (rank + 1) % size):

    then all four processes call (let us replace the formula (rank + 1) % size, accordingly):

    MPI_Isend(&data, 1, MPI_INT, (rank + 1) % size, 0, MPI_COMM_WORLD, &request);
    

    • 进程 0 从进程 (0 + 1) % 4 发送消息 ->1;
    • 进程 1 从进程 (1 + 1) % 4 发送消息 ->2;
    • 进程 2 从进程 (2 + 1) % 4 发送消息 ->3;
    • 进程 3 从进程 (3 + 1) % 4 发送消息 ->0;
    • 所以 (rank + 1) % size 被用作一个技巧,这样当你到达最后一个等级时,它会返回第一个的等级.

      So (rank + 1) % size is used as a trick so that when you reach the last rank it returns back the rank of the first.

      所有这些都是为了构建以下接收/发送消息的模式 0 ->1 ->2 ->3 ->0.

      All this to build the following pattern of recv/send message 0 -> 1 -> 2 -> 3 -> 0.

      您可能已经注意到 MPI_RecvMPI_Send 分别被调用了 3 次和 4 次.即使您没有遇到任何与此相关的问题,通常,不执行相同数量的 MPI_Recv/MPI_Send 调用可能会导致死锁.如果不使用 (rank + 1) % size 而只是使用 rank + 1 并过滤掉调用 MPI_Isend,如下:

      As you might have noticed MPI_Recv and MPI_Send are called 3 and 4 times, respectively. And even though you did not experienced any issue regarding this, commonly, not performing the same number of MPI_Recv/MPI_Send calls might cause deadlocks. This can be avoid if instead of using (rank + 1) % size you use just rank + 1 and filter out the last processes from calling the MPI_Isend, as follows:

      if(rank + 1 < size)
        MPI_Isend(&data, 1, MPI_INT, (rank + 1) 0, MPI_COMM_WORLD, &request);
      

      这意味着进程 3 不会向进程 0 发送消息,但这没关系,因为进程 0 无论如何都不希望收到任何消息.

      This means that Process 3 will not send a message to Process 0, but that is okey since Process 0 does not expect to receive any message anyway.

      运行示例:

      #include <iostream>
      #include <mpi.h>
      #include <unistd.h>
      
      int main(int argc, char* argv[])
      {
          MPI_Init(&argc, &argv);
          MPI_Request request;
          MPI_Status  status;
      
          int size, rank, data;
      
          MPI_Comm_rank(MPI_COMM_WORLD, &rank);
          MPI_Comm_size(MPI_COMM_WORLD, &size);
      
          if (rank>0) {
             MPI_Irecv(&data, 1, MPI_INT, rank - 1, 0,  MPI_COMM_WORLD,&request);
             MPI_Wait(&request, &status);
             std::cout << "Rank " << rank << " has received message with data " << data<< " from rank " << rank - 1
                    << std::endl;
          }
      
          std::cout << "Hello from rank " <<rank << " out of " << size<< std::endl;
          data=rank;
      
         if(rank + 1 < size){
             MPI_Isend(&data, 1, MPI_INT, (rank + 1) 0, MPI_COMM_WORLD, &request);
          }
          MPI_Wait(&request, &status);
          MPI_Finalize();
      
          return 0;
      }
      

      输出:使用 4 个进程可能的输出:

      Output: With 4 process a possible output:

      Hello from rank 0 out of 4
      Rank 1 has received message with data 0 from rank 0
      Hello from rank 1 out of 4
      Rank 2 has received message with data 1 from rank 1
      Hello from rank 2 out of 4
      Rank 3 has received message with data 2 from rank 2
      Hello from rank 3 out of 4
      

      这篇关于简单的 hello world 非阻塞 MPI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆