Popen的Python文档声明:
警告使用communic()而不是.stdin.write,.stdout.read或.stderr.read来避免因任何其他OS管道缓冲区填满和阻止子进程而导致的死锁。
现在,我正在试图弄清楚这种僵局是如何发生的以及原因。
我的心理模型:subproccess为stdout / err生成一些东西,这是缓冲的,填充缓冲区之后,它被刷新到subproccess的stdout / err,它通过管道发送到父进程。
从文档中可以看出,pipe有自己的缓冲区,当它被填充或子进程终止时,它被刷新到父进程。
无论哪种方式(使用管道缓冲区),我都不完全确定如何发生死锁。我唯一能想到的是某种“全局”OS管道缓冲进程将会争取,这听起来很奇怪。另一个是更多进程将共享相同的管道,这不应该自己发生。
有人可以解释一下吗?
答案 0 :(得分:6)
小心,这有一个微妙的错误。
我的心理模型:子流程产生 什么东西stdout / err,这是 缓冲并填充缓冲区后 它被冲到了stdout / err subproccess,通过发送 管道到父进程。
缓冲区由父进程和子进程共享。
子进程向stdout生成一些东西,这是父进程应该从中读取的缓冲区。
当填充缓冲区时,写入将停止,直到清空缓冲区为止。 Flush对管道没有任何意义,因为两个进程共享相同的缓冲区。
刷新到磁盘意味着设备驱动程序必须将字节向下推送到设备。刷新套接字意味着告诉TCP / IP停止等待累积缓冲区并发送内容。刷新到控制台意味着停止等待换行符并将字节通过设备驱动程序推送到设备。
答案 1 :(得分:1)
当两个缓冲区(stdin和stdout)都已满时,可能会发生死锁:程序正在等待向外部程序写入更多输入,外部程序正在等待您首先从其输出缓冲区中读取。
这可以通过使用非阻塞I / O并正确区分缓冲区来解决。您可以尝试让它自己运作,但communicate()
只是为您做到了。