如何在Python 2.7中写入超时的管道?

时间:2017-08-24 18:55:29

标签: python linux macos python-2.7

我打开管道与Python中的子进程通信。通信是双向的,并且在两个过程的整个生命周期内都是连续的。

import os
r, w = os.pipe()
# fork, exec, etc.
child_stdin = os.fdopen(w, "w")

如果对方已满,写入管道可能会无限期阻止。在macOS和Linux上,默认管道缓冲区为65535字节,并且尝试推送更多内容将阻止:

import os
r, w = os.pipe()
f = os.fdopen(w, "w")
f.write("\0" * 65535)
f.write("\0")  # blocks indefinitely

使用select.select来测试管道是否准备就绪并且它允许您指定超时,但是它告诉您的是管道可以接收一些数据,而不是它必须接收数据量您希望立即发送。例如,这也将无限期地阻止:

import os
import select
r, w = os.pipe()
f = os.fdopen(w, "w")
f.write("\0" * 65534)
select.select((), (f,), ())
# select returned, therefore we can write?...
f.write("\0\0")  # blocks indefinitely

您可以将管道设置为非阻塞,并将其用作超时的构建块(select,再写一些,select直到准备好,再写一些,等等。但是f.write没有返回任何内容,因此您不知道成功写出了多少数据:

import os
import fcntl
r, w = os.pipe()
fcntl.fcntl(w, fcntl.F_SETFL, fcntl.fcntl(w, fcntl.F_GETFL) | os.O_NONBLOCK))
f = os.fdopen(w, "w")
f.write("\0" * 65535)
f.write("\0")  # returns immediately without writing anything
# no idea how much data was actually written :/

那么在Python 2.7中使用超时写入管道的正确方法是什么?我此时应该下降到os.write吗?

解决方案必须同时适用于macOS和Linux。

0 个答案:

没有答案