来自使用 Popen.wait() 的文档可能:
deadlock when using stdout=PIPE and/or stderr=PIPE and the child process generates enough output to a pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that.
在交流 docs它写道:
The data read is buffered in memory, so do not use this method if the data size is large or unlimited
如何重现这种有问题的行为,并使用 Popen.communicate() 看到这一点修复了吗?
死锁意味着持有资源的进程之间会发生一些循环等待并且永远卡住。
这里的循环依赖是什么?等待子进程终止的 Python 进程是一种等待。另一个是什么?在下面的场景中,谁在等待什么?
it blocks waiting for the OS pipe buffer to accept more data
最佳答案
这很简单。
创建一个输出大量文本而不读取输出的进程:
p = subprocess.Popen(["ls","-R"],stdout=subprocess.PIPE)
p.wait()
一段时间后,标准输出管道已满,进程被阻塞。
这是一个死锁情况,因为子进程不能再写入输出,直到它被消耗(即:从不),并且 python 进程等待子进程完成。
为避免死锁,您可以使用读取行循环:
p = subprocess.Popen(["ls","-R"],stdout=subprocess.PIPE)
for line in p.stdout:
# do something with the line
p.wait()
communicate
也修复了这个问题,但也修复了更棘手的情况,即输出和错误流都被重定向到单独的流(在这种情况下,上面的幼稚循环仍然可能死锁)。假设你有一个编译过程
p = subprocess.Popen(["gcc","-c"]+mega_list_of_files,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
现在你想得到这个输出,所以你做:
output = p.stdout.read()
不幸的是,反而弹出了很多错误,在您读取输出流时阻塞了错误流:再次死锁。
尝试改为读取错误流,可能会发生完全相反的情况:大量 stdout 输出阻塞了您的进程。
communicate
使用多线程能够同时处理输出和错误流并将它们分开,没有阻塞的风险。唯一需要注意的是,您无法实时逐行控制进程输出/打印程序输出:p = subprocess.Popen(["gcc","-c"]+mega_list_of_files,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
output,error = p.communicate()
return_code = p.wait()
关于python - 使用 Popen.wait() 时重现死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49728472/