Python流子进程标准输出和错误输出压缩不起作用

5

已经有很多答案解决了如何做这个一般的事情,但是我的主要问题是为什么这种方法不起作用?

我正在尝试从子进程“实时流式传输”stdout和stderr。 我可以通过执行以下操作来实现:

import sys
import subprocess

def run_command(cmd):
    process = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE)

    for out in iter(process.stdout.readline, b''):
        print(out)

    for err in iter(process.stderr.readline, b''):
        print(err)

run_command(['echo', 'hello', 'world']) # should print hello world
run_command(['rm', 'blarg223'])  # Should print to stderr (file doesnt exist)

这样做可以给我带来以下结果:

b'hello world\n'
b'rm: cannot remove \xe2\x80\x98blarg223\xe2\x80\x99: No such file or directory\n'

然而,这会导致一个问题,因为它只实时流式传输标准输出(stdout),然后在结束时打印所有错误信息。所以我认为可以使用以下方法来解决这个问题:
def run_command(cmd):
    process = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE)

    for out, err in zip(iter(process.stdout.readline, b''), iter(process.stderr.readline, b'')):
        print(out)
        print(b'Error: ' + err)

但是,这并没有产生任何输出。为什么使用zip不起作用?

你是否期望标准输出和标准错误输出的行之间始终存在一对一的对应关系?你试图将这些行成对处理。 - user2357112
如果标准输出(stdout)和标准错误(stderr)没有产生相同数量的输出(超过一个阈值),那么这两个代码示例都可能导致死锁。 - jfs
@J.F.Sebastian 怎么可能呢?我已经测试过了,它似乎可以工作。你能举个死锁发生的例子吗? - Nick Humrich
如果你无法创建产生死锁的示例,请提出一个单独的问题。 - @NickHumrich - jfs
1个回答

3

当其中一个迭代器完成时,zip就停止。

在你提供的每个示例中,其中一个流(stdout/stderr)是空的。因此,zip将不会产生任何内容。

要解决这个问题,您应该使用itertools.zip_longest。


@NickHumrich:在一般情况下,zip_longest()无法解决死锁问题。问题中的代码是有问题的。如果您想要分别读取stdout/stderr作为“实时流”,则应该同时读取管道,例如使用线程,或使用a select()-loop - jfs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接