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

如何在Python基于GLib主循环的程序中后台监控子进程输出

问题原因

你之前把监控逻辑放到Idle回调失败的核心原因是process.stderr.readline()是阻塞调用,Idle回调会在主循环空闲时执行,一旦调用阻塞读取,整个GLib主循环会被挂起,其他任务都无法正常调度。

可行实现方案

GLib原生提供了IO监听能力,你可以用GIOChannel把管道的文件描述符注册到主循环,只有当有输出可读、进程退出、出错时才会触发回调,完全不会阻塞主循环运行,示例代码(Python + PyGObject 环境)如下:

import subprocess
from gi.repository import GLib

def handle_subprocess_output(channel, condition, process):
    # 处理可读事件
    if condition & GLib.IO_IN:
        output = channel.readline().strip()
        if output:
            if '<some-output>' in output:
                print('<something>')
            elif '<some-other-output>' in output:
                print('something-else')
    # 处理进程退出、出错事件
    if condition & (GLib.IO_HUP | GLib.IO_ERR | GLib.IO_NVAL):
        # 回收子进程资源,避免僵尸进程
        process.wait()
        # 停止监听该IO通道
        return GLib.SOURCE_REMOVE
    # 继续监听
    return GLib.SOURCE_CONTINUE

def main():
    # 启动子进程,stderr绑定管道
    process = subprocess.Popen(
        '<some-command>',
        shell=True,
        stderr=subprocess.PIPE,
        text=True # 直接返回字符串,不需要额外转str
    )
    # 把stderr的文件描述符包装为GIOChannel
    io_channel = GLib.IOChannel.unix_new(process.stderr.fileno())
    # 注册IO事件监听
    GLib.io_add_watch(
        io_channel,
        GLib.PRIORITY_DEFAULT,
        GLib.IO_IN | GLib.IO_HUP | GLib.IO_ERR | GLib.IO_NVAL,
        handle_subprocess_output,
        process # 把进程对象传给回调
    )
    # 启动主循环
    loop = GLib.MainLoop()
    loop.run()

if __name__ == "__main__":
    main()

注意事项

  • 如果是C语言开发的GLib程序,逻辑完全一致:用g_io_channel_unix_new()包装管道fd,调用g_io_add_watch()注册回调即可
  • 不要在回调里执行耗时操作,否则还是会阻塞主循环
  • 子进程退出后必须调用wait()回收进程资源,避免产生僵尸进程

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 16:15:08