MPI (mpi4py) - 如果第一个 test() 返回 false,则 irecv() 和 test() 不会在循环中工作

Posted

技术标签:

【中文标题】MPI (mpi4py) - 如果第一个 test() 返回 false,则 irecv() 和 test() 不会在循环中工作【英文标题】:MPI (mpi4py) - irecv() and test() don't work in loop if first test() returned false 【发布时间】:2021-09-21 14:47:03 【问题描述】:

我正在运行几个异步通信的进程。

进程 1 每隔一段时间向进程 2 发送一条消息。 进程 2 每隔一段时间检查一次消息。 如果没有消息可用,进程 2 会继续执行其他操作,直到下一个间隔。

问题是:如果进程 2 在进程 1 发送任何内容之前开始尝试接收,那么所有后续接收也会失败。反之,如果进程 1 在进程 2 尝试接收之前发送了任何消息,则所有后续接收都成功。

使用 Python 和 mpi4py 的最小示例:

import sys
from time import sleep

from mpi4py import MPI

comm = MPI.COMM_WORLD
rank = comm.Get_rank()

if rank == 0:
    print("Process 1 started")
    sys.stdout.flush()
    sleep(3)

    for i in range(10):
        sys.stdout.flush()

        comm.send(f"Message i", dest=1)

        print(f"Process 1 sent message i")
        sys.stdout.flush()

        sleep(1)

elif rank == 1:
    print("Process 2 started")
    sys.stdout.flush()
    sleep(1)

    for i in range(1000):
        req = comm.irecv()
        success, message = req.test()
        if success:
            print(f"Process 2 received message")
        else:
            print(f"Process 2 didn't receive anything on attempt i")
        sys.stdout.flush()

        sleep(3)

给出以下输出:

Process 1 started
Process 2 started
Process 2 didn't receive anything on attempt 0
Process 1 sent message 0
Process 1 sent message 1
Process 2 didn't receive anything on attempt 1
Process 1 sent message 2
Process 1 sent message 3
Process 2 didn't receive anything on attempt 2
Process 1 sent message 4
Process 1 sent message 5
...

从进程 1 中删除第一个 sleep 会导致成功的发送/接收链:

Process 1 started
Process 2 started
Process 1 sent message 0
Process 1 sent message 1
Process 2 received Message 0
Process 1 sent message 2
Process 1 sent message 3
Process 2 received Message 1
Process 1 sent message 4
Process 1 sent message 5
Process 1 sent message 6
Process 2 received Message 2

我的实现中缺少什么来使第一个版本正常工作?

【问题讨论】:

如果在接收器中为irecv 指定source=0 会怎样? 【参考方案1】:

您的问题是您反复发出Irecv,但您只保留最后一个请求。因此,该消息可以被早期的Irecv 捕获,但您不再需要它了。您可以通过只执行一次Irecv 来解决此问题,然后循环执行Test

但是,这遇到了一个非常微妙的问题,Test 是本地的,并且可能不会强制“进步”。 ProbeIprobe 都强制通信进行。

因此,您的修复并不是真正关于TestProbe 之间的区别,而是您已经消除了您的初始代码发出许多接收的问题。

【讨论】:

【参考方案2】:

原来问题在于使用test() 作为检查是否有等待传入消息的方法。正确的方法是使用probe or iprobe(不确定mpi4py中两者的实际区别是什么):

修复后的工作示例:

if rank == 0:
    print("Process 1 started")
    sys.stdout.flush()
    sleep(3)

    for i in range(10):
        sys.stdout.flush()

        comm.send(i, dest=1)

        print(f"Process 1 sent message i")
        sys.stdout.flush()

        sleep(1)

elif rank == 1:
    print("Process 2 started")
    sys.stdout.flush()
    sleep(1)

    for i in range(1000):
        probe = comm.iprobe()
        if probe:
            message = comm.recv()
            print(f"Process 2 received message")
        else:
            print(f"Process 2 didn't receive anything on attempt i")
        sys.stdout.flush()

        sleep(3)

https://www.mpich.org/static/docs/latest/www3/MPI_Iprobe.html

【讨论】:

以上是关于MPI (mpi4py) - 如果第一个 test() 返回 false,则 irecv() 和 test() 不会在循环中工作的主要内容,如果未能解决你的问题,请参考以下文章

mpi4py 的 MPI 数据传输错误

mpi4py - 使用矩阵列的类型

通过 MPI [MPI4py] 发送复数时的 MPI_ERR_TRUNCATE

mpi4py | comm.bcast 不起作用

如何让 mpi4py 在 Windows 上工作

如何使用 MS HPC Server 2008 R2 的 MPI 堆栈成功编译 mpi4py?