python - 使用 Popen.wait() 时重现死锁

标签 python python-3.x subprocess deadlock popen

来自使用 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/

相关文章:

python - 读取以列名作为行的 csv 文件并编辑日期时间

python - 计算 python 列表中标记之间的出现次数

python - 迭代地将字符 [a-c] 分配给 Pandas Dataframe 中的行,直到列长度结束

python - 使用 subprocess.Popen() 或 subprocess.check_call() 时程序卡住

python - QuantLib: yield 曲线的碰撞

Python CSV : Find identical data in two CSV files and copy corresponding data

python - 用 np.NaN 替换 pandas 数据框中的缺失值(以字符串形式给出)

Python:从脚本中打开一个名为 xls 的 unicode 文件

python - 为什么使用 Python 子进程调用 ssh 会破坏外部 bash 循环

python - 无法转置 numpy 3D 数组