如何检查非阻塞减少的完成情况?

How to check completion of non-blocking reduce?

我不清楚如何在 MPI 中正确使用非阻塞集合,特别是 MPI_Ireduce() 在这种情况下:

假设我想从根等级中收集一笔款项:

int local_cnt;
int total_cnt;
MPI_Request request;
MPI_Ireduce(&local_cnt, &total_cnt, 1, MPI_INT, MPI_SUM, 0, MPI_WORLD_COMM, &request);

/* now I want to check if the reduce is finished */

if (rank == 0) {
    int flag = 0;
    MPI_Status status;
    MPI_Test(&request, &flag, &status);
    if (flag) {
        /* reduce is finished? */
    }
}

这是检查非阻塞 reduce 是否完成的正确方法吗?我的困惑来自两个方面:第一,根进程是否可以或应该使用 MPI_Test() 检查它,因为这只对根有意义?其次,由于 MPI_Test() 是本地操作,这个本地操作如何知道操作完成?它确实需要完成所有进程,对吧?

您必须检查所有参与等级是否完成,而不仅仅是根。

从用户的角度来看,您需要了解通信的完成情况,因为您不能对提供给非阻塞操作的内存做任何事情。 IE。如果你发送一个像 local_cnt 这样的局部作用域变量,你不能在确认操作完成之前写入它或离开它的作用域。

确保完成的一个选项是调用 MPI_Test,直到它最终 returns flag==true。仅当您可以在对 MPI_Test:

的调用之间做一些有用的事情时才使用它
{
    int local_cnt;
    int total_cnt;

    // fill local_cnt on all ranks

    MPI_Request request;
    MPI_Ireduce(&local_cnt, &total_cnt, 1, MPI_INT, MPI_SUM, 0, MPI_WORLD_COMM, &request);

    int flag;
    do {

        // perform some useful computation
        MPI_Status status;
        MPI_Test(&request, &flag, &status);
    } while (!flag)
}

如果您在两次调用之间无事可做,请不要循环调用 MPI_Test。而是使用 MPI_Wait,它会阻塞直到完成。

{
    int local_cnt;
    int total_cnt;

    // fill local_cnt on all ranks

    MPI_Request request;
    MPI_Ireduce(&local_cnt, &total_cnt, 1, MPI_INT, MPI_SUM, 0, MPI_WORLD_COMM, &request);

    // perform some useful computation
    MPI_Status status;
    MPI_Wait(&request, &status);
}

请记住,如果您根本没有有用的计算,并且由于死锁原因不需要非阻塞,请首先使用阻塞通信。如果您有多个正在进行的非阻塞通信,则有 MPI_WaitanyMPI_WaitsomeMPI_Waitall 及其测试变体。

Zulan 出色地回答了您问题的第一部分。

MPI_Reduce() returns 当

  • 可以在非根等级上覆盖发送缓冲区
  • 结果在根等级上可用(这意味着所有等级都已完成)

所以非根等级无法知道根等级是否完成。如果你确实需要这些信息,那么你需要手动添加一个MPI_Barrier()。也就是说,您通常 不需要 需要此信息,如果您认为您确实需要它,则您的应用可能有问题。

如果您使用非阻塞集合(例如 MPI_Wait() 对应于 MPI_Ireduce() 在非根等级上完成:这仅仅意味着发送缓冲区可以被覆盖。