本文介绍了肯定已发送消息后,为什么MPI_Iprobe返回false?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用MPI_Iprobe来测试带有给定标签的消息是否已经挂起.

I want to use MPI_Iprobe to test whether a message with a given tag is already pending.

但是,MPI_Iprobe的行为并不像我期望的那样.在下面的示例中,我将消息从多个任务发送到单个任务(等级0).然后在等级0上,我等待几秒钟,以便有足够的时间完成MPI_Isends.然后,当我运行MPI_Iprobe时,它会返回标志false.如果在(阻塞的)MPI_Probe之后重复执行此操作,则它将返回true.

However, the behaviour of MPI_Iprobe isn't quite as I was expecting.In the example below, I send messages from multiple tasks to a single task (rank 0). Then on rank 0, I wait several seconds to allow plenty of time for the MPI_Isends to complete. Then when I run MPI_Iprobe it returns with flag false. If I repeat after a (blocking) MPI_Probe, then it returns true.

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

int main(int argc, char *argv[])
{
  int rank;
  int numprocs;
  int tag;
  int receive_tag;
  int flag=0;
  int number;
  int recv_number=0;

  MPI_Request request;
  MPI_Status status;

  MPI_Init(&argc,&argv);
  MPI_Comm_rank(MPI_COMM_WORLD,&rank);
  MPI_Comm_size(MPI_COMM_WORLD,&numprocs);

  // rank 0 receives messages, all others send messages
  if (rank > 0 ) {
    number = rank;
    tag = rank;
    MPI_Isend(&number, 1, MPI_INT, 0, tag, MPI_COMM_WORLD,&request); // send to rank 0
    printf("Sending tag : %d \n",tag);
   }
   else if (rank == 0) {

   sleep(5); // [seconds] allow plenty of time for all sends from other tasks to complete

   receive_tag = 3; // just try and receive a single message from task 1

   MPI_Iprobe(MPI_ANY_SOURCE,receive_tag,MPI_COMM_WORLD,&flag,&status);
   printf("After MPI_Iprobe, flag = %d \n",flag);

   MPI_Probe(MPI_ANY_SOURCE,receive_tag,MPI_COMM_WORLD,&status);
   printf("After MPI_Probe, found message with tag : %d \n",receive_tag);

   MPI_Iprobe(MPI_ANY_SOURCE,receive_tag,MPI_COMM_WORLD,&flag,&status);
   printf("After second MPI_Iprobe, flag = %d \n",flag);

   // receive all the messages
   for (int i=1;i<numprocs;i++){
     MPI_Recv(&recv_number, 1, MPI_INT, MPI_ANY_SOURCE, i, MPI_COMM_WORLD,&status);
     printf("Received : %d \n",recv_number);
   }

 }
 MPI_Finalize();
}

给出以下输出:

Sending tag : 4
Sending tag : 3
Sending tag : 2
Sending tag : 5
Sending tag : 1
After MPI_Iprobe, flag = 0
After MPI_Probe, found message with tag : 3
After second MPI_Iprobe, flag = 1
Received : 1
Received : 2
Received : 3
Received : 4
Received : 5

为什么mpi_iprobe第一次返回"false"?

Why does mpi_iprobe return 'false' the first time?

任何帮助将不胜感激!

在Hristo Iliev回答之后,我现在有以下代码:

after the answer by Hristo Iliev I now have the following code:

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

int main(int argc, char *argv[])
{
  int rank;
  int numprocs;
  int tag;
  int receive_tag;
  int flag=0;
  int number;
  int recv_number=0;

  MPI_Request request;
  MPI_Status status;

  MPI_Init(&argc,&argv);
  MPI_Comm_rank(MPI_COMM_WORLD,&rank);
  MPI_Comm_size(MPI_COMM_WORLD,&numprocs);

  // rank 0 receives messages, all others send messages
  if (rank > 0 ) {
    number = rank;
    tag = rank;

    MPI_Isend(&number, 1, MPI_INT, 0, tag, MPI_COMM_WORLD,&request); // send to rank 0
    printf("Sending tag : %d \n",tag);

    // do stuff

    MPI_Wait(&request,&status);
    printf("Sent tag : %d \n",tag);

   }
    else if (rank == 0) {

    sleep(5); // [seconds] allow plenty of time for all sends from other tasks to complete

    receive_tag = 3; // just try and receive a single message from task 1

    MPI_Iprobe(MPI_ANY_SOURCE,receive_tag,MPI_COMM_WORLD,&flag,&status);
    printf("After MPI_Iprobe, flag = %d \n",flag);

    MPI_Probe(MPI_ANY_SOURCE,receive_tag,MPI_COMM_WORLD,&status);
    printf("After MPI_Probe, found message with tag : %d \n",receive_tag);

    MPI_Iprobe(MPI_ANY_SOURCE,receive_tag,MPI_COMM_WORLD,&flag,&status);
    printf("After second MPI_Iprobe, flag = %d \n",flag);

    // receive all the other messages
    for (int i=1;i<numprocs;i++){
       MPI_Recv(&recv_number, 1, MPI_INT, MPI_ANY_SOURCE, i, MPI_COMM_WORLD,&status);
    }

 }
 MPI_Finalize();
}

哪个给出以下输出:

Sending tag : 5
Sending tag : 2
Sending tag : 1
Sending tag : 4
Sending tag : 3
Sent tag : 2
Sent tag : 1
Sent tag : 5
Sent tag : 4
Sent tag : 3
After MPI_Iprobe, flag = 0
After MPI_Probe, found message with tag : 3
After second MPI_Iprobe, flag = 1

推荐答案

您正在使用MPI_Isend来发送消息. MPI_Isend 启动一个异步(后台)数据传输.除非已对请求进行了MPI_Wait*MPI_Test*调用之一,否则可能不会发生实际的数据传输.一些MPI实现具有(或可以配置为)后台进程线程,即使没有对请求进行任何等待/测试,该线程也将继续发送操作,但是不应依赖这种行为.

You are using MPI_Isend in order to send the messages. MPI_Isend initiates an asynchronous (background) data transfer. The actual data transfer might not happen unless one of the MPI_Wait* or MPI_Test* calls has been made on the request. Some MPI implementations have (or can be configured so) background progression threads that will progress the send operation even if no wait/test has been done on the request, but one should not rely on such behaviour.

只需将MPI_Isend替换为MPI_Send或在前者之后添加MPI_Wait(&request);(请注意,紧随其后的MPI_Isend + MPI_Wait等同于MPI_Send).

Simply replace MPI_Isend with MPI_Send or add MPI_Wait(&request); after the former (mind though that MPI_Isend + MPI_Wait immediately after is equivalent to MPI_Send).

MPI_Iprobe旨在用于繁忙的等待中,即:

MPI_Iprobe is intended to be used in busy waits, i.e.:

while (condition)
{
   MPI_Iprobe(...,&flag,...);
   if (flag)
   {
      MPI_Recv(...);
      ...
   }
   // Do something, e.g. background tasks
}

在实际的MPI实现中,现实生活中的消息传输是相当复杂的事情.通常将操作分成多个部分,然后排队.执行这些部分称为 progression ,它是在MPI库中的各个点完成的,例如,在进行通信调用时,或者在后台执行(如果该库实现了后台进程线程).调用MPI_Iprobe当然可以使事情进展,但是不能保证一个调用就足够了. MPI标准规定:

Real-life message transfers in actual MPI implementations are quite complicated things. Operations are usually split in multiple parts that are then queued. Executing that parts is called progression and it is done at various points in the MPI library, for example when a communication call is made or in background if the library implements a background progression thread. Calling MPI_Iprobe certainly does progress things but there is no guarantee that a single call will suffice. The MPI standard states:

请注意最终使用的是 .如何进行进度是非常特定于实现的.将来自5个连续调用的以下输出与MPI_Iprobe(原始代码+紧密循环)进行比较:

Note the use of eventually. How progression is being done is very implementation-specific. Compare the following output from 5 consecutive calls to MPI_Iprobe (your original code + a tight loop):

打开MPI 1.6.5,无需进度线程:

Open MPI 1.6.5 w/o progression thread:

# Run 1
After MPI_Iprobe, flag = 0
After MPI_Iprobe, flag = 0
After MPI_Iprobe, flag = 0
After MPI_Iprobe, flag = 1
After MPI_Iprobe, flag = 1

# Run 2
After MPI_Iprobe, flag = 0
After MPI_Iprobe, flag = 1
After MPI_Iprobe, flag = 1
After MPI_Iprobe, flag = 1
After MPI_Iprobe, flag = 1

# Run 3
After MPI_Iprobe, flag = 0
After MPI_Iprobe, flag = 0
After MPI_Iprobe, flag = 0
After MPI_Iprobe, flag = 0
After MPI_Iprobe, flag = 0

在相同的MPI程序的多个执行之间没有观察到一致性,并且在第三次运行中,在5次调用MPI_Iprobe之后,标记仍然是false.

No consistency between several executions of the same MPI program is observed and in the 3rd run the flag is still false after 5 invocations of MPI_Iprobe.

英特尔MPI 4.1.2:

Intel MPI 4.1.2:

# Run 1
After MPI_Iprobe, flag = 0
After MPI_Iprobe, flag = 0
After MPI_Iprobe, flag = 1
After MPI_Iprobe, flag = 1
After MPI_Iprobe, flag = 1

# Run 2
After MPI_Iprobe, flag = 0
After MPI_Iprobe, flag = 0
After MPI_Iprobe, flag = 1
After MPI_Iprobe, flag = 1
After MPI_Iprobe, flag = 1

# Run 3
After MPI_Iprobe, flag = 0
After MPI_Iprobe, flag = 0
After MPI_Iprobe, flag = 1
After MPI_Iprobe, flag = 1
After MPI_Iprobe, flag = 1

很明显,英特尔MPI与Open MPI的进度有所不同.

Obviously Intel MPI progresses things differently than Open MPI.

这两个实现之间的差异可以通过以下事实来解释:MPI_Iprobe应该是一个很小的探针,因此应该花费尽可能少的时间.另一方面,进行进度会花费时间,并且在单线程MPI实现中,可能进行进度的唯一时间点是对MPI_Iprobe的调用(在特定情况下).因此,MPI实现者必须决定每次调用MPI_Iprobe实际实际进行了多少操作,并在调用完成的工作量和所需的时间之间取得平衡.

The difference between the two implementations can be explained by the fact that MPI_Iprobe is supposed to be a tiny probe and therefore it should take as less time as possible. Progression on the other hand takes time and in single-threaded MPI implementations the only point in time where progression is possible is the call to MPI_Iprobe (in that particular case). Therefore the MPI implementer has to decide how much is actually progressed by each call to MPI_Iprobe and strike a balance between the amount of work done by the call and the time it takes.

对于MPI_Probe,情况有所不同.这是一个阻塞的呼叫,因此它可以不断进行,直到出现匹配的消息(更确切地说是其信封)为止.

With MPI_Probe things are different. It is a blocking call and therefore it is able to constantly progresses until a matching message (and more specifically its envelope) appears.

这篇关于肯定已发送消息后,为什么MPI_Iprobe返回false?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-28 16:48