我打开管道与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。