You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用subprocess.Popen运行脚本时stdout/stderr显示BufferedReader问题求助

subprocess.Popen无法获取stdout/stderr输出解决方案

根本原因

subprocess.Popen 是异步非阻塞接口,调用后仅启动子进程,不会等待子进程执行完成,也不会自动读取管道中的输出内容。你代码中直接打印的proc.stdout和proc.stderr是缓冲区IO对象,不是实际输出内容。而subprocess.run是阻塞接口,会等待子进程运行结束后自动收集stdout、stderr的内容,因此可以直接拿到输出。

解决思路

方案1:等待进程结束后读取全部输出

调用proc.wait()方法阻塞等待子进程执行完成,再调用read()读取缓冲区内容,示例代码如下:

proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(proc.pid)
# 阻塞等待子进程执行完成
proc.wait()
# 读取输出并解码,编码可根据你的系统环境调整
stdout = proc.stdout.read().decode('utf-8')
stderr = proc.stderr.read().decode('utf-8')
print(f'err is: {stderr}')
print(f'stdout: {stdout}')

方案2:实时读取子进程输出

如果子进程运行时间较长,不想等待进程结束再拿输出,可以逐行读取缓冲区内容,实现实时输出:

# text=True参数可以直接返回字符串,无需手动解码
proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
print(proc.pid)
# 实时读取标准输出
for line in iter(proc.stdout.readline, ''):
    print(f'stdout: {line.strip()}')
# 标准输出读取完成后读取标准错误
for line in iter(proc.stderr.readline, ''):
    print(f'err: {line.strip()}')
# 等待进程退出获取返回码
proc.wait()

方案3:解决子进程输出缓冲问题

部分脚本默认开启标准输出缓冲,仅当缓冲区满或进程退出时才会输出内容到管道,遇到这种情况可以在启动Python脚本时添加-u参数禁用缓冲,修改command如下:

command = ['python3', '-u', PosixPath('myrepo/myscript.py'), '-c', PosixPath('myrepo/config.json')]

线程终止时关闭子进程实现

你可以将Popen实例存为线程的属性,在停止线程触发event时主动终止子进程,修改后的线程类示例如下:

class my_thread(threading.Thread):
    def __init__(self, event): 
        super(my_thread, self).__init__()
        self._event = event
        self.proc = None

    def run(self):    
        command = ['python3', '-u', PosixPath('myrepo/myscript.py'), '-c', PosixPath('myrepo/config.json')]
        self.proc =  subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
        print(self.proc.pid)
        # 读取输出的同时检测停止事件
        while not self._event.is_set():
            line = self.proc.stdout.readline()
            if not line:
                break
            print(f'stdout: {line.strip()}')
        # 停止事件触发后终止仍在运行的子进程
        if self.proc.poll() is None:
            self.proc.terminate()
            self.proc.wait()

内容的提问来源于stack exchange,提问作者Maryam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 17:06:03