python subprocess:从管道读取而不关闭它

时间:2014-01-03 05:56:20

标签: python bash shell subprocess pipe

我有一个向stdout写入连续字节流的进程。 我有另一个进程从第一个进程的stdout读取然后完成。 但是我发现当第二个进程完成时,它会关闭管道(我认为),因此进程1停止运行。

我尝试了两种不同的方式:

shell 1中的

# make fifo
mkfifo /tmp/camera
# stream video from my webcam to the pipe
ffmpeg -y -f v4l2 -r 10 -i /dev/video0 -f avi /tmp/camera
shell 2中的

# attach to pipe and take a snapshot
rrmpeg -y -r 1 -f avi -i /tmp/camera -vframes 1 -s 160x120 -f image2 image1.jpg

我也在shell 2中尝试了相同的结果:

tail -f /tmp/camera

当shell 2中的进程停止时,它会终止进程1.为什么?

我尝试的第二件事是使用python子进程:

from subprocess import Popen, PIPE
import shlex, time

stream = Popen(shlex.split("ffmpeg -y -f v4l2 -r 10 -i /dev/video0 -f avi -"), stdout=PIPE)
while True:
    time.sleep(3)
    snap = Popen(shlex.split("rrmpeg -y -r 1 -f avi -i - -vframes 1 -s 160x120 -f image2 image1.jpg"), stdin=stream.stdout)

它第一次通过循环,但当snap进程超出范围时,stream进程就会死掉。

有没有办法在没有关闭的情况下从进程1中读取一些流?

1 个答案:

答案 0 :(得分:1)

是的,有一种方法可以永久地继续管道编写器。为此,你必须确保

  1. 至少有一个读者保持管道打开(没有阅读就好了) - 或 -
  2. 编写器忽略了SIGPIPE并很好地处理了write()错误(即再次尝试)
  3. 第二个选项不是那么简单(不更改/检查编写器的源代码),因为没有阅读器的管道上的write()不会阻塞(一旦读者在那里)。

    对于第一个选项,请确保您的第一个阅读器打开fifo / pipe,不读取任何内容,然后永久阻止/睡眠,而不会死亡。

    让任何连续的读者做这项工作。他们可以打开一个fifo(命名管道),或者必须从读取结束打开的进程中分叉(它们继承了filedescriptor)。

    这样就不会生成SIGPIPE,一旦管道缓冲区已满,write()将阻止编写器。

    man 7 pipe告诉你更多信息。

    (注意:如果write()阻止了意外的长时间,某些程序可能会感到困惑。例如,一些经常查看挂钟的应用程序。)

    关于“当shell 2中的进程停止时,它会终止进程1.为什么?”

    进程1可能被SIGPIPE杀死(我没有检查源代码),它在没有阅读器的管道上尝试write()时获得。