我不清楚如何在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? */
}
}
这是检查是否完成非阻塞归约的正确方法吗?我的困惑来自两个方面:一,是否可以使用MPI_Test()
进行根进程检查,因为这仅对根有意义?其次,由于MPI_Test()
是本地操作,因此该本地操作如何知道操作已完成?它确实需要完成所有过程,对吧?
答案 0 :(得分:1)
您必须检查所有参与等级的完成情况,而不仅仅是根。
从用户的角度出发,您需要了解通信的完成情况,因为您不得对非阻塞操作提供的内存进行任何操作。即如果您发送local_cnt
之类的本地范围变量,则在确认操作已完成之前,无法对其进行写入或保留其范围。
确保完成的一种方法是调用MPI_Test
,直到最终返回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_Waitany
,MPI_Waitsome
,MPI_Waitall
及其测试变体。
答案 1 :(得分:1)
祖兰妙妙地回答了您问题的第一部分。
MPI_Reduce()
返回时间
因此,非根级别无法知道根级别是否已完成。如果确实需要此信息,则需要手动添加MPI_Barrier()
。话虽如此,您通常不需要此信息,并且如果您认为确实需要此信息,则您的应用可能存在问题。
如果您使用非阻塞集合(例如,与MPI_Wait()
对应的MPI_Ireduce()
在非根目录级别上完成),则情况仍然如此:这仅意味着发送缓冲区可以被覆盖。