为什么我的Popen管堵?

时间:2017-12-15 08:58:41

标签: python subprocess pipe

我试图将一些数据提供给连接的一系列进程 通过管道。但是,我无法将其关闭。

p1 = subprocess.Popen("sort", stdin=subprocess.PIPE, stdout=subprocess.PIPE)
p2 = subprocess.Popen("uniq", stdin=p1.stdout, stdout=subprocess.PIPE)

p1.communicate(r"""
a
b
c
a""")
out, _ = p2.communicate()
print(out)

现在该程序正在等待。是否有另一种方式我应该通知p1输入结束?

- 注意:我在Windows上运行

2 个答案:

答案 0 :(得分:2)

您需要在第一个程序上关闭stdin。

需要注意的一些事项:

  1. 管道之间有缓冲区(subprocess.PIPE为您创建的),每个平台和用途的大小各不相同。不要担心这一点,因为它不像以下那样重要:

  2. 在这种情况下,sort要求在能够排序之前读取完整的输入(如果您不知道它们是什么,则无法对事物进行排序)。

  3. 由于2,它有自己的缓冲区来收集并等待文件描述符被关闭,表示它已完成;)

    编辑:这是我正在制作的例子。我发现直接使用管道更加个性化,因为您可以在生成流程之前单独构建输入:

    In [2]: import os
       ...: import subprocess
       ...: 
       ...: # A raw os level pipe, which consists of two file destriptors
       ...: # connected to each other, ala a "pipe".
       ...: # (This is what subprocess.PIPE sets up btw, hence it's name! ;)
       ...: read, write = os.pipe()
       ...: 
       ...: # Write what you want to it. In python 2, remove the `b` since all `str`ings are `byte` strings there.
       ...: os.write(write, b"blahblahblah")
       ...: 
       ...: # Close stdin to signal completion of input
       ...: os.close(write)
       ...: 
       ...: # Spawn process using the pipe as stdin
       ...: p = subprocess.Popen(['cat'], stdin=read)
       ...: 
    blahblahblah
    

    另外,请确保p.wait()完成此过程,否则您最终可能会遇到尚未获得完整结果的情况。

答案 1 :(得分:1)

免责声明:此处不是专家。我之前没有使用communicate(),但是......

首先,在阅读docs for communicate时,它意味着从正在运行的进程的stdout / stderr中读取数据:

  

从stdout和stderr读取数据

所以我想你的python程序会读取p1执行sort的输出。或者确切地说,在我的Linux机器上,行为似乎不是确定性的 - 有时它是Python代码,有时它是p2/uniq读取p1/sort的标准输出。我猜他们只是在争夺数据。

看起来communicate()的东西是某种组合,对你的用例(p1/sort)来说有点太多了。这对p2/uniq很好。

另一方面,如果你尝试过:

import subprocess

p1 = subprocess.Popen("sort", stdin=subprocess.PIPE, stdout=subprocess.PIPE)
p2 = subprocess.Popen("uniq", stdin=p1.stdout, stdout=subprocess.PIPE)

p1.stdin.write(r"""
a
b
c
a""")
p1.stdin.close()
out, _ = p2.communicate()
print(out)
它似乎有效。