为什么pipe.close()在python多进程的pipe.recv()中不引发EOFError?

23 投票
2 回答
7517 浏览
提问于 2025-04-16 20:45

我正在使用Python的多进程模块,通过管道在进程之间发送简单的对象。文档上说,如果管道已经关闭,调用pipe.recv()应该会抛出一个EOFError错误。但是,我的程序在调用recv()时只是一直卡在那里,根本没有检测到管道已经关闭。

示例:

import multiprocessing as m

def fn(pipe):
    print "recv:", pipe.recv()
    print "recv:", pipe.recv()

if __name__ == '__main__':
    p1, p2 = m.Pipe()
    pr = m.Process(target=fn, args=(p2,))
    pr.start()

    p1.send(1)
    p1.close()  ## should generate EOFError in remote process

输出看起来是这样的:

recv: 1
<blocks here>

有没有人能告诉我我哪里做错了?我在Linux和windows/cygwin上都有这个问题,但在Windows的原生Python上却没有。

2 个回答

2

根据这个解决方案,我发现使用os.close(pipe.fileno())可以立即关闭管道,而使用pipe.close()则需要等所有的进程或子进程结束后才能关闭。你可以试试这个方法。需要注意的是:在使用这个方法后,你不能再用pipe.close(),不过pipe.closed仍然会返回“false”。所以你可以这样做,让代码看起来更整洁:

os.close(pipe.fileno())
pipe=open('/dev/null')
pipe.close()
15

被分叉出来的(子)进程会继承父进程的文件描述符的一个副本。所以即使父进程对p1调用了“关闭”,子进程仍然有一个副本是打开的,底层的内核对象并没有被释放。

要解决这个问题,你需要在子进程中关闭管道的“写”端,像这样:

def fn(pipe):
    p1.close()
    print "recv:", pipe.recv()
    print "recv:", pipe.recv()

撰写回答