警告使用
communicate()
而不是.stdin.write
,.stdout.read
或.stderr.read
,以避免死锁是由于其他OS管道缓冲区中的任何一个填满并阻塞了子进程。
我试图理解为什么这会造成僵局。对于某些背景,我并行生成N个进程:
for c in commands:
h = subprocess.Popen(c, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
handles.append(h)
然后逐个打印每个进程的输出:
for handle in handles:
while handle.poll() is None:
try:
line = handle.stdout.readline()
except UnicodeDecodeError:
line = "((INVALID UNICODE))\n"
sys.stdout.write(line)
if handle.returncode != 0:
print(handle.stdout.read(), file=sys.stdout)
if handle.returncode != 0:
print(handle.stderr.read(), file=sys.stderr)
有时实际上确实会造成僵局。不幸的是,文档中建议使用communicate()
的建议对我来说不起作用,因为此过程可能要花几分钟的时间才能运行,而且我不希望它在这段时间内显得死气沉沉。它应该实时打印输出。
我有几种选择,例如更改bufsize
参数,在每个句柄中轮询不同的线程等。但是,为了确定解决此问题的最佳方法,我想我需要了解根本原因因为僵局在首位。显然,这与缓冲区大小有关,但是又如何呢?我可以假设所有这些进程都共享一个OS内核对象,并且由于我只消耗了其中一个进程的缓冲区,其他进程将其填满,在这种情况下,上述选项2可能会解决该问题。但这也许不是真正的问题。
任何人都可以阐明这一点吗?
父进程和子进程之间的双向通信使用两个单向管道。每个方向一个。好的,stderr是第三个,但是想法是相同的。
一个管道有两个末端,一个末端用于书写,一个末端用于读取。管道的容量为4K,在现代Linux上现在为64K。可以期望在其他系统上具有相似的值。这意味着,编写器可以毫无问题地写入管道,但管道不会满,然后管道将写满并且阻塞写入,直到读取器从另一端读取一些数据为止。