【问题标题】:How do I avoid deadlock when using subprocess.Popen to connect multiple processes by pipes?使用 subprocess.Popen 通过管道连接多个进程时如何避免死锁?
【发布时间】:2021-09-20 10:55:46
【问题描述】:

这是 @Omry Yadan 在 2018 年 12 月 9 日的回答 How do subprocess.Popen pipes work in Python? 的后续问题。我需要创建一个三个程序管道并从所有三个程序中收集标准错误和返回代码。我当前的解决方案(如下)基于 2018 年 12 月 9 日的答案,挂起。粘贴到 shell 中的等效命令很快完成。

从标准输出到标准输入的数据量在 Mbyte 范围内。最终的标准输出以及三个标准错误预计会小得多。

#!/usr/bin/env python3

cmd1 = ["gzip", "-dc", "some_file.gz"]
cmd2 = ["filtering_program", "some", "arguments"]
cmd3 = ["collection_program", "some", "arguments"]

p1 = Popen(cmd1, stdout=PIPE, stderr=PIPE)
p2 = Popen(cmd1, stdin=p1.stdout, stdout=PIPE, stderr=PIPE)]
p3 = Popen(cmd1, stdin=p2.stdout, stdout=PIPE, stderr=PIPE)]
(outcome_stdout, outcome_stderr) = p3.communicate()
p1.wait()
p2.wait()

【问题讨论】:

    标签: python python-3.x subprocess


    【解决方案1】:

    请注意以下已记录的问题。另请注意,管道缓冲区要么增长到(MacOS)默认限制为 65536 字节(现代 Linux)

    Popen.wait

    注意当使用 stdout=PIPE 或 stderr=PIPE 时,这将死锁,并且子进程会向管道生成足够的输出,从而阻塞等待 OS 管道缓冲区接受更多数据。使用管道时使用 Popen.communicate() 来避免这种情况。

    Popen.stderr

    警告使用communicate() 而不是.stdin.write、.stdout.read 或.stderr.read 以避免由于任何其他操作系统管道缓冲区填满并阻塞子进程而导致的死锁。

    【讨论】:

    • 谢谢。我确实看到了关于潜在死锁的说明,但我不清楚如何使用 Popen.communicate() 来避免死锁。我应该调用 p1.communicate() 和 p2.communicate() 吗?相对于 p*.wait() 调用的顺序是什么?
    • 您知道有什么比docs.python.org/3/library/subprocess.html 更好的子流程参考吗?我正在尝试做的似乎是对包的自然使用,在 shell 中运行很简单,因此应该有一个简单的 python 解决方案。但是我无法从那些文档中弄清楚如何完成它。
    • 这取决于您作为首选开发风格尝试完成的工作,以及尝试添加并发性的原因将改变答案。我很想先串联使用 run() ,除非你有理由增加复杂性。死锁和并发问题,尤其是在使用较低级别的 Popen() 时,比我用 100 个字符回答的要复杂得多。这是一个有助于理解陷阱的视频youtu.be/Bv25Dwe84g0 就我个人而言,我会使用 async for loops,因为死锁很难,而且任务并不是真正的并行。
    • 感谢您的链接。事实上,我确实计划添加并发,但希望在没有它的情况下让它工作,因为我预计调试非并发版本会更容易。我在脚本中将 run() 用于其他命令,但是一旦我同时尝试两个管道命令,它就会死锁。添加 shell=true 并没有太大帮助——我认为问题在于从一个进程到另一个进程的数据量。我没有考虑使用一系列单个命令 run()s——我认为这将是管道数据完全保存在 python 对象中。这可能是“最佳”解决方案。谢谢!
    猜你喜欢
    • 2010-09-22
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 2019-12-06
    • 1970-01-01
    相关资源
    最近更新 更多