如何在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
相关产品推荐
相关产品推荐

