【问题标题】:Python subprocesses with several pipes具有多个管道的 Python 子进程
【发布时间】:2013-10-15 17:39:12
【问题描述】:

我知道如何使用子进程执行多个“嵌套”管道,但是我还有另一个疑问。我想做以下事情:

p1=Popen(cmd1,stdout=PIPE)
p2=Popen(cmd2,stdin=p1.stdout)
p3=Popen(cmd3,stdin=p1.stdout)

考虑到 p3 使用 p1.stdout 而不是 p2.stdout。问题是做p2之后,p1.stdout是空白的。请帮帮我!

【问题讨论】:

    标签: python subprocess pipe


    【解决方案1】:

    您不能将同一个管道发送到两个不同的进程。或者更确切地说,如果你这样做了,它们最终会访问同一个管道,这意味着如果一个进程读取了某些内容,那么另一个进程将不再可以使用它。

    您需要做的是以某种方式“发送”数据。


    如果您不需要在数据进入时对其进行流式传输,您可以从p1 读取所有输出,然后将其作为输入发送到p2 和p3。这很简单:

    output = check_output(cmd1)
    p2 = Popen(cmd2, stdin=PIPE)
    p2.communicate(output)
    p3 = Popen(cmd3, stdin=PIPE)
    p3.communicate(output)
    

    如果您只需要 p2 和 p3 并行运行,您可以在一个线程中分别运行它们。

    但如果您确实需要实时流式传输,则必须更仔细地进行连接。如果您可以确定p2 和p3 将始终使用它们的输入,而不会阻塞,比p1 提供的速度更快,您可以在没有线程的情况下执行此操作(只需循环p1.stdout.read()),否则,您'将需要每个消费者进程的输出线程,以及Queue 或其他方式来传递数据。请参阅source code 至communicate,了解有关如何同步单独线程的更多想法。

    【讨论】:

      【解决方案2】:

      如果您想将子进程的输出复制到其他进程而不一次读取所有输出,那么这里有一个 @abarnert's suggestion 的实现来循环 p1.stdout 来实现它:

      from subprocess import Popen, PIPE
      
      # start subprocesses
      p1 = Popen(cmd1, stdout=PIPE, bufsize=1)
      p2 = Popen(cmd2, stdin=PIPE, bufsize=1)
      p3 = Popen(cmd3, stdin=PIPE, bufsize=1)
      
      # "tee" the data
      for line in iter(p1.stdout.readline, b''): # assume line-oriented data
          p2.stdin.write(line)
          p3.stdin.write(line)
      
      # clean up
      for pipe in [p1.stdout, p2.stdin, p3.stdin]:
          pipe.close()
      for proc in [p1, p2, p3]:
          proc.wait()
      

      【讨论】:

      • 除非您不能确定p2 或p3 永远不会阻塞或花费太长时间来维护管道,否则就会出现死锁。要安全地执行此操作,您确实需要select 或三个线程。
      • @abarnert:我不明白你怎么会在这里陷入僵局,除非进程在这种情况下表现得病态,select 和线程都无济于事。当您从 same 进程读取/写入多个管道时,您可能会将它与这种情况混淆(在这种情况下很容易死锁)。
      • 如果p2 只是没有从它的管道中读取,你的p2.stdin.write 将阻塞直到它准备好。这意味着p3 不会得到它的数据,因为p2 还没有准备好。而p1 将继续喷出数据,直到它填满管道。您可以使用this 之类的方法来解决这两个问题(当然,代价是缓冲无限量的数据)。
      • @abarnert:这是我提到的病态(和无趣)行为:select 或线程无法强制 p2 读取数据。
      • 但他们可以允许p1 和p3 继续进行,即使p2 阻塞了一段时间。
      猜你喜欢
      • 2019-12-01
      • 2015-05-04
      • 1970-01-01
      • 1970-01-01
      • 2012-03-21
      • 2017-03-10
      • 2011-04-05
      • 2016-06-05
      • 1970-01-01
      相关资源
      最近更新 更多