【问题标题】:How to tell when data through a pipe has ended如何判断通过管道的数据何时结束
【发布时间】:2016-12-06 16:55:16
【问题描述】:

在我的 python 程序中,我有两个 subprocesses 由一个 pipe 互连,一个连接到 stdin,另一个连接到 stdout。我的问题是,当数据流结束时,子进程会挂起,直到我按下ctrl+c。在我看来,子流程正在打开我的管道。如果我能知道数据何时流经管道,我可以手动关闭它。

def write(tag_name):
    p_r, p_w = os.pipe()
    pv = subprocess.Popen('pv', stdin=None, stdout=p_w)
    dd = subprocess.Popen('dd bs=64k of=/dev/nst0'.split(), stdin=p_r, stdout=None)
    dd.wait()

【问题讨论】:

    标签: python linux pipe


    【解决方案1】:

    只是不要使用os.pipe(),你可以将子进程stdout直接传递给另一个进程stdin,像这样:

    def write(tag_name):
        pv = subprocess.Popen('pv', stdin=None, stdout=subprocess.PIPE)
        dd = subprocess.Popen('dd bs=64k of=/dev/nst0'.split(), stdin=pv.stdout, stdout=None)
        dd.wait()
    

    当第一个命令结束时,管道被破坏(而不是需要手动关闭的os.pipe()),所以它也结束了第二个命令并且脚本可以继续/结束。

    我测试了一个简单的管道命令,并使用os.pipe() 它在最后阻塞,如您所描述的,但是当第一个进程以我的修改结束时退出。

    【讨论】:

    • 我在pv 线上收到OSError: [Errno 9] Bad file descriptor
    • 看python手册subprocess.STDOUT只能作为Popen.stderr的参数。不过,通过stdout=subprocess.PIPE 可以按您所说的那样工作。
    • 对不起,错字!!固定为subprocess.PIPE
    【解决方案2】:

    您需要一个非阻塞的解决方案。 看看我的解决方案:https://github.com/vesellov/bitdust.devel/blob/master/system/nonblocking.py

    而且可以这样调用(没测试过代码):

    import nonblocking, time
    p = nonblocking.Popen('pv'.split(), shell=True, )
    p.make_nonblocking()
    while 1:
        if p.state() == nonblocking.PIPE_CLOSED:
            # pipe closed, stop
            return break
        if p.state() == nonblocking.PIPE_READY2READ:
            newchunk = p.recv(1024)
            if newchunk == '':
                # EOF reached, stop
                break
            # do something with the data here
            # you can send it to second stream
        try:
           time.sleep(0.01)
        except KeyboardInterrup:
           break
    

    因此,当您调用 dd.wait() 时,它会阻塞,这就是您的 Ctrl-C 不起作用的原因。你需要手动处理这个......非阻塞流在 Python 中并不是一个简单的故事。退房Twisted project,你可以找到很多很酷的东西:-)

    【讨论】:

    • 有趣的解决方案,唯一的缺点是它的带宽限制为 100KB/s。在我的情况下,dd.wait() 并没有停止Ctrl-C,实际上按下Ctrl-C 会导致管道被垃圾收集并且子进程干净地退出。
    • 是的,您可以根据需要调整time.sleep() 间隔。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-28
    • 1970-01-01
    • 1970-01-01
    • 2014-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多