这是代码的一部分。

    if(rank==0) {
        temp=10000;
        var=new char[temp] ;
        MPI_Send(&temp,1,MPI_INT,1,tag,MPI_COMM_WORLD);
        MPI_Send(var,temp,MPI_BYTE,1,tag,MPI_COMM_WORLD);
            //MPI_Wait(&req[0],&sta[1]);
    }
    if(rank==1) {
        MPI_Irecv(&temp,1,MPI_INT,0,tag,MPI_COMM_WORLD,&req[0]);
        MPI_Wait(&req[0],&sta[0]);
        var=new char[temp] ;
        MPI_Irecv(var,temp,MPI_BYTE,0,tag,MPI_COMM_WORLD,&req[1]);
        MPI_Wait(&req[0],&sta[0]);
    }
    //I am talking about this MPI_Barrier


    MPI_Barrier(MPI_COMM_WORLD);
    cout << MPI_Wtime()-t1 << endl ;
    cout << "hello " << rank  << " " << temp << endl ;
        MPI_Finalize();
}

1.使用MPI_Barrier时-如所料,所有过程花费的时间几乎相同,大约为0.02

2.不使用MPI_Barrier()-时,根进程(发送消息)等待一些额外的时间。
(MPI_Wtime -t1)相差很大,并且根进程花费的时间约为2秒。

如果我不是真的错,那么MPI_Barrier仅用于使所有正在运行的进程处于同一级别。所以为什么我使用MPI_Barrier()的时间不为2秒(所有进程的最小值,例如root进程)。请解释 ?

最佳答案

感谢Wesley Bland注意到您在同一请求上等待了两次。这是实际发生情况的解释。

MPI中有一种称为异步(非阻塞)操作的进程。那就是实际的转移发生的时候。 MPI库中的进度可能以多种不同方式发生,也可能在许多不同点发生。当您发布异步操作时,它的进程可能会无限期推迟,甚至直到有人调用MPI_WaitMPI_Test或某些调用会导致新消息被推到发送/接收队列或从发送/接收队列中拉出的那一点起。因此,在启动非阻塞操作后尽快调用MPI_WaitMPI_Test非常重要。

Open MPI支持后台进程线程,即使不满足上一段中的条件,该线程也会小心地进行操作。如果从未在请求​​句柄上调用MPI_WaitMPI_Test。构建库时必须显式启用它。默认情况下未启用它,因为后台进程会增加操作的延迟。

在您的情况下,发生的情况是您第二次在接收器中调用MPI_Wait时正在等待不正确的请求,因此第二个MPI_Irecv操作的进程被推迟。该消息的大小超过40 KiB(10000乘以4字节+信封开销),超过了Open MPI(32 KiB)中的默认急切限制。此类消息是使用会合协议(protocol)发送的,该协议(protocol)要求发送和接收操作都需要发布和处理。接收操作不会继续进行,因此等级0的发送操作会阻塞,直到某个时间点,等级1中的MPI_Finalize调用的清理例程最终会进行接收。

当您调用MPI_Barrier时,它会导致未完成接收的进展,几乎就像对MPI_Wait的隐式调用一样。这就是为什么排名第0的发送快速完成并且两个进程都按时进行的原因。

请注意,MPI_Irecv紧随其后是MPI_Wait等效于简单地调用MPI_Recv。后者不仅更简单,而且不太容易像您所做的那样输入简单的错字。

07-24 09:47