我花了三天时间寻找答案,所以如果已经解决这个问题,我希望你能忍受我,并且我已经找到了解决方案。 我正在使用Fortran(eugh!)但这是一个通用的MPI查询。
场景(本例简化):
CALL MPI_SEND(end_of_run, 1, MPI_LOGICAL, filter_rank_id, c_tag_open_rcv, mpi_coupling_comms, mpi_err)
问题出现在进程2中...它忙于执行MPI_Recv / MPI_Send对,我无法摆脱它。我为其他两个进程设置了一个非阻塞接收并存储了请求句柄:
DO model_rank_id= 0, 1
!Set up a non-blocking receive to get notification of end of model run for each model
end_run = end_model_runs(model_rank_id) !this is an array of booleans initialised to FALSE
CALL MPI_IRECV(end_run, 1, MPI_LOGICAL, model_rank_id, &
c_tag_open_rcv, coupling_comms, mpi_request_handle, mpi_err)
!store the handle in an array
request_handles(model_rank_id) = mpi_request_handle
END DO
其中model_rank_id是MPI通信器中的进程号,即0或1。
稍后,忙着做所有那些接收/发送对,我总是检查是否有任何东西到达缓冲区:
DO model_rank_id= 0, 1
IF (end_model_runs(model_rank_id) .EQV. .FALSE.) THEN
CALL MPI_TEST(request_handles(model_rank_id), run_complete, mpi_status, mpi_err)
IF (run_complete .eqv. .FALSE.) THEN
!do stuff... receive/process/send
ELSE
!run is complete
!___________removed this as I realised it was incorrect__________
!get the stop flag for the specific process
CALL MPI_RECV(end_run, 1, MPI_LOGICAL, model_rank_id, &
c_tag_open_rcv, coupling_comms, mpi_err)
!____________end_________________________________________________
!store the stop flag so I can do a logical 'AND' on it and break out when
!both processes have sent their message
end_model_runs(model_rank_id) = end_run
END IF
END IF
END DO
请注意,此代码段包含在循环中,该循环一直持续到所有停止标志为TRUE。
我知道它相当复杂,但这不是那么难,可以吗?如果有人能够看到错误的错误,甚至建议更好的方法来做到这一点。
提前非常感谢。
答案 0 :(得分:0)
您的计划可能会停留在MPI_RECV
来电。原因是MPI_TEST
返回的肯定完成标记表示MPI_IRECV
已收到消息。除非发件人发送另一条带有相同标签的邮件,否则MPI_RECV
只会阻止并等待,在您的情况下可能无限期。除此之外,您发出两个具有相同接收缓冲区的MPI_IRECV
调用,这可能不是您真正想要做的,因为end_run = end_model_runs(model_rank_id)
不会将数组元素的地址复制到end_run
而是它的价值。
您的代码应如下所示:
DO model_rank_id= 0, 1
!Set up a non-blocking receive to get notification of end of model run for each model
CALL MPI_IRECV(end_model_runs(model_rank_id), 1, MPI_LOGICAL, model_rank_id, &
c_tag_open_rcv, coupling_comms, request_handle, ierr)
!store the handle in an array
request_handles(model_rank_id) = request_handle
END DO
...
DO model_rank_id= 0, 1
IF (end_model_runs(model_rank_id) .EQV. .FALSE.) THEN
CALL MPI_TEST(request_handles(model_rank_id), run_complete, status, ierr)
IF (run_complete .eqv. .FALSE.) THEN
!do stuff... receive/process/send
ELSE
!run is complete
!the stop flag is ALREADY in end_model_runs(model_rank_id)
!do a logical 'AND' on it and break out when
END IF
END IF
END DO
作为旁注,使用您自己的以mpi_
开头的标识符是个糟糕的主意,因为它们可能会与MPI库提供的符号发生冲突。您应该将mpi_
视为保留前缀,并在命名自己的变量,子例程等时不要使用它。我已在上面的代码中为您修复了这个。
答案 1 :(得分:0)
经过大量的实验,我最终解决了这个问题,实际上很简单(不是一直都是这样吗?)
问题是由于流程0& 1可以结束并发布他们的“我已经完成”的消息OK,但是进程2处于如此紧密的循环中进行测试和recv / send对(为了清晰起见,在原始的过去中省略了两组send / recv的外部循环) ,测试将失败,并且该过程将粘在阻塞MPI_RECV
。
首先我尝试了睡眠(3)使其工作,但它无法在每个循环上睡觉而没有对性能产生真正的不良影响,然后我尝试了MPI_IPROBE
但遇到与测试相同的问题。最后,围绕MPI_IPROBE
的超时做了伎俩,因此:
DO iter1 = 1, num_models
!Test each model in turn and ensure we do the comms until it has finished
IF (end_model_runs(iter1) .EQV. .FALSE.) THEN
model_rank_id= models(iter1)
now = TIME()
DO WHILE (TIME() .LT. now + timeout)
msg_flag = .FALSE.
CALL MPI_IPROBE(model_rank_id, c_tag, coupling_comms, &
msg_flag, empi_status, empi_err)
IF (msg_flag .EQV. .TRUE.) THEN
!Message waiting
EXIT
END IF
END DO
IF (msg_flag .EQV. .TRUE.) THEN
CALL MPI_RECV(state_vector, num_state_params, MPI_DOUBLE_PRECISION, &
model_rank_id, c_tag, coupling_comms, empi_status, empi_err)
ELSE !no message waiting, flag should be False, i.e. the run *has* finished
end_model_runs(iter1) = .NOT. msg_flag
END IF
END IF
END DO
这个代码在一个循环中,一旦end_model_runs
的所有成员都是TRUE
就会中断。
我希望这可以帮助别人 - 并为他们节省三天的努力!