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

Asyncio如何正确读取子进程的标准输出?

Asyncio如何正确读取子进程的标准输出?

我来帮你梳理下问题的根源,以及对应的解决办法:

问题出在哪?

你的stopwatch.py里用了print(start),但Python的输出缓冲策略会根据stdout的类型变化:

  • 当stdout是终端时,默认是行缓冲,print后会立刻把内容输出到屏幕;
  • 但当我们把stdout重定向到管道(也就是设置stdout=asyncio.subprocess.PIPE)时,Python会切换成块缓冲——意思是输出会先攒在缓冲区里,攒够一定大小才会发送到管道。

这就导致你的子进程虽然每秒都在print,但内容一直留在缓冲区里,没传到父进程那边:

  • 你调用readline()时会因为没有可读取的内容挂起;
  • 杀掉进程后再读,缓冲区里的内容可能还没来得及刷新,所以读到空字符串。

解决办法(三种任选其一)

1. 修改子进程代码,强制刷新输出

在stopwatch.py的print语句里加上flush=True,让每次print都立刻把内容刷到管道:

print(start, flush=True)

2. 启动子进程时禁用Python缓冲(不用改子进程代码)

通过设置环境变量PYTHONUNBUFFERED=1,强制Python不使用输出缓冲:

import os  # 记得导入os

async def start(self):
    env = os.environ.copy()
    env['PYTHONUNBUFFERED'] = '1'
    self.robot = await asyncio.create_subprocess_exec(
        *self.cmd,
        stdout=asyncio.subprocess.PIPE,
        env=env
    )

3. 用-u参数启动Python解释器(不用改子进程代码)

直接在启动命令里加上-u参数,让Python进入无缓冲模式:

self.cmd = ["python", "-u", "stopwatch.py", "10"]

额外优化:读取所有输出

原代码里readline()只能读一行,如果你想获取子进程运行期间的所有输出,可以在stop方法里循环读取直到stdout关闭:

async def stop(self):
    if self.robot:
        self.robot.kill()
        # 循环读取所有剩余输出
        while True:
            line = await self.robot.stdout.readline()
            if not line:
                break
            # 转成字符串并去掉换行符
            print(f"子进程输出:{line.decode().strip()}")
        await self.robot.wait()
    self.robot = None

备注:内容来源于stack exchange,提问作者Black Jack

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.17 12:38:02