Python multiprocessing pipe recv() 文档不清晰还是我漏掉了什么?

7 投票
1 回答
9033 浏览
提问于 2025-04-17 08:48

最近我在学习如何使用Python的多进程模块,并且在阅读官方文档。在16.6.1.2. 进程间交换对象部分,有一个简单的例子,讲的是如何用管道来交换数据。

而在16.6.2.4. 连接对象中,有一句话提到:“如果没有可以接收的内容,并且另一端已经关闭,就会引发EOFError错误。”

所以,我对这个例子进行了修改,如下所示。在我看来,这应该会触发一个EOFError异常:因为没有发送任何数据,并且发送端已经关闭。

修改后的代码:

from multiprocessing import Process, Pipe

def f(conn):
    #conn.send([42, None, 'hello'])
    conn.close()

if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    p = Process(target=f, args=(child_conn,))
    p.start()
    #print parent_conn.recv()   # prints "[42, None, 'hello']"
    try:
        print parent_conn.recv()
    except EOFError:
        pass
    p.join()

但是,当我在我的Ubuntu 11.04机器上,使用Python 2.7.2运行这个修改后的例子时,脚本却卡住了。

如果有人能告诉我我遗漏了什么,我会非常感激。

1 个回答

10

当你用 mp.Process 启动一个新进程时,子进程会继承父进程的管道。也就是说,子进程和父进程之间有一种通信的方式。子进程如果关闭了 conn,父进程那边的 child_conn 仍然是打开的,这样管道的引用计数就还是大于0,所以不会出现EOFError(文件结束错误)。

要想得到EOFError,你需要在父进程和子进程中都关闭管道的一端:

import multiprocessing as mp

def foo_pipe(conn):
    conn.close()

def pipe():
    conn = mp.Pipe()
    parent_conn, child_conn = conn
    proc = mp.Process(target = foo_pipe, args = (child_conn, ))
    proc.start()
    child_conn.close()  # <-- Close the child_conn end in the main process too.
    try:
        print(parent_conn.recv())
    except EOFError as err:
        print('Got here')
    proc.join()

if __name__=='__main__':
    pipe()

撰写回答