当前位置: 首页 > 面试题库 >

如何从subprocess.communicate()中捕获python中的流输出

濮阳国兴
2023-03-14
问题内容

目前,我有这样的事情:

self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE)
out, err = self.process.communicate()

我正在运行的命令将输出流式传输,在继续之前,我需要阻塞该过程。

如何做到这一点,以便可以捕获流输出并通过stdout打印流输出?设置时stdout=subprocess.PIPE,我可以捕获输出,但不会打印输出。如果我不进行操作stdout=subprocess.PIPE,它将打印输出,但communicate()将返回None

有没有一种解决方案可以满足我的要求,即在进程终止/完成之前提供阻塞,并避免此处提到的缓冲区问题和管道死锁问题?

谢谢!


问题答案:

我可以想到一些解决方案。

#1:您可以直接进入源代码以获取,复制和粘贴的代码communicate,并添加可打印每行内容的代码以及对它们进行缓冲的代码。(如果您可能stdout由于死锁的父母而被自己阻止,则可以改用athreading.Queue或其他东西。)这显然有点麻烦,但这很简单,而且很安全。

但实际上,这communicate很复杂,因为它需要完全通用,并处理您不需要的情况。您需要的只是中心技巧:在问题上抛出线程。read您只需要一个专用的读取器线程,它不会使任何操作变慢或在调用之间阻塞。

像这样:

self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE)
lines = []
def reader():
    for line in self.process.stdout:
        lines.append(line)
        sys.stdout.write(line)
t = threading.Thread(target=reader)
t.start()
self.process.wait()
t.join()

您可能需要在reader线程中进行一些错误处理。我不确定100%是否可以readline在这里安全使用。但这要么有效,要么接近。

#2:或者您可以创建一个包装器类,该包装器类接受一个文件对象,并在每次有人访问它时发球到stdout/
。然后,手动创建管道,并传递包裹的管道,而不是使用automagic
。这个问题与#1完全相同(意味着没有问题,或者您需要使用a或其他内容(如果可以阻止))。stderr``read``PIPE``Queue``sys.stdout.write

像这样:

class TeeReader(object):
    def __init__(self, input_file, tee_file):
        self.input_file = input_file
        self.tee_file = tee_file
    def read(self, size=-1):
        ret = self.input_file.read(size)
        if ret:
            self.tee_file.write(ret)
        return ret

换句话说,它包装了一个文件对象(或类似对象的东西),并像一个文件对象一样工作。(当使用时PIPE,它process.stdout是Unix上的真实文件对象,但可能只是在Windows上具有类似的行为。)您需要委派的任何其他方法input_file都可以直接委派,而无需进行任何额外包装。要么试试这个,看看有什么方法communicate得到AttributeException,正在寻找和代码的那些明确,或者做一般的__getattr__伎俩委托的一切。PS,如果您担心这种“文件对象”的想法,即磁盘存储,请阅读Wikipedia上的Everything是一个文件。

#3:最后,您可以获取PyPI上的“异步子进程”模块之一,或将其包含在twisted其他异步框架中或使用它。(这使得它 能够 避免死锁问题,但它不
保证 -你还是要确保服务管道正常。)



 类似资料:
  • 问题内容: 我正在使用从运行约一分钟的进程中读取stdout。 我该如何stdout以流方式打印出该流程的每一行,以便可以看到生成的输出,但仍然阻止该流程终止,然后再继续? 似乎一次给出所有输出。 问题答案: 这是一个简单的示例(不检查错误): 如果ls结束太快,则while循环可能会在你读取所有数据之前结束。 你可以通过以下方式在中捕获其余部分:

  • 问题内容: 我正在尝试从Python内部进行比特币付款。在bash中,我通常会这样做: 因此,例如: 如果成功,我会得到一个交易ID作为输出,但是如果我尝试转账大于我的比特币余额的金额,则会得到以下输出: 现在,在我的Python程序中,我尝试按以下方式进行付款: 如果有足够的余额,则可以正常工作,但是如果没有足够的余额,则会输出以下内容: 它不包括我在命令行中得到的错误。所以我的问题是;如何从P

  • 问题内容: 我正在使用对对象执行某些操作的Python库 并更改它。这样做时,它会向stdout打印一些统计信息,我希望掌握这些信息。正确的解决方案是更改以返回相关信息, 但是开发人员需要一段时间才能解决此问题。作为一种解决方法,我考虑过解析对stdout的任何写入。 如何捕获代码中两点之间的stdout输出,例如 ? 问题答案: 试试这个上下文管理器: 用法: 现在是一个包含函数调用打印的行的列

  • 问题内容: 我正在研究启动多个进程和数据库连接的python脚本。我不时地想用信号杀死脚本,我想进行一些清理。 在Perl中,我可以这样做: 如何在Python中做类似的事情? 问题答案: 用以下方式注册你的处理程序: 代码改编自此处。

  • 我有一个Spring Boot应用程序,它是移动/Web应用程序的API。其中一个endpoint接受如下的MultipartFile(图像或视频): 当调用该方法时,我获取文件内容并将其保存在某个地方。但是,我注意到一个错误 - 如果我在上传过程中终止了移动应用程序上的网络连接,我在API端没有得到任何类型的,我最终会得到一个截断的字节数组: 所以问题是:如何确保直播不会中断? 使用Spring

  • 问题内容: 是否可以从Python脚本捕获Python解释器的输出? 是否可以从Python脚本捕获Windows CMD的输出? 如果是这样,我应该研究哪个librar(y | ies)? 问题答案: 如果您正在谈论的是脚本的“父级” python解释器或CMD.exe,那么不可能,这是不可能的。在每个类似POSIX的系统中(似乎现在您正在运行Windows,并且可能有一些我不知道的怪癖,YMM

  • 问题内容: 我了解到,在Python中执行命令时,应该使用子进程。我想要实现的是通过ffmpeg对文件进行编码,并观察程序输出,直到文件完成。Ffmpeg将进度记录到stderr。 如果我尝试这样的事情: 调用child.communicate()后,程序无法继续执行,并等待命令完成。还有其他方法可以跟踪输出吗? 问题答案: communication()阻塞直到子进程返回,所以循环中的其余各行仅

  • 问题内容: 由于某些其他原因,我使用的c ++共享库将一些文本输出到标准输出。在python中,我想捕获输出并 保存到一个变量中 。关于重定向标准输出,还有许多类似的问题,但在我的代码中不起作用。 在第5行中, func() 将调用共享库,共享库生成的文本仍输出到控制台!如果将 func() 更改 为print“ hello” ,则可以使用! 我的问题是: 如何将c ++共享库的stdout捕获