【问题标题】:Why does my Popen pipe block?为什么我的 Popen 管道阻塞?
【发布时间】:2017-12-15 08:58:41
【问题描述】:

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

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上运行

【问题讨论】:

  • FWIW,(在 Linux 上运行)程序确实结束了(并且大多数时候不打印任何内容)

标签: python subprocess pipe


【解决方案1】:

您需要在第一个程序上关闭标准输入。

需要注意的一些事项:

  1. 管道之间存在缓冲区(subprocess.PIPE 为您创建的内容),其大小因平台和使用情况而异。暂时不要担心这一点,因为它的相关性不如:

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

由于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() 完成该过程,否则您可能会遇到尚未获得完整结果的情况。

【讨论】:

    【解决方案2】:

    免责声明:这里不是专家。我之前没用过communicate(),但是……

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

    从标准输出和标准错误读取数据

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

    看起来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)
    

    它似乎有效。

    【讨论】:

      猜你喜欢
      • 2010-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-15
      • 1970-01-01
      • 2016-09-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多