aiomonitor能发现事件循环卡顿是因为它定期采样事件循环时间与任务栈快照,识别出“某任务运行超阈值(默认1s)”的异常状态,不依赖代码埋点,而是从运行时底层观测;普通日志仅记录主动写入的点,无法捕获静默发生的调度停滞。

为什么 aiomonitor 能发现事件循环卡顿,而普通日志不行
因为卡顿本质是事件循环长时间没调度新任务,不是报错也不是超时——它静默发生。普通日志只记录你主动写的点,而 aiomonitor 是通过定期采样 asyncio.get_event_loop().time() 和任务栈快照,识别出「某任务已运行超过阈值(默认 1s)」的异常状态。它不依赖你的代码埋点,而是从运行时底层观测。
注意:它只能监控当前进程内主事件循环,无法跨进程或跨线程捕获阻塞。
如何启动 aiomonitor 并确认它在工作
安装后直接集成进你的异步应用,无需改业务逻辑:
pip install aiomonitor
在你的 main() 或服务启动处加入:
立即学习“Python免费学习笔记(深入)”;
import aiomonitor
import asyncio
loop = asyncio.get_event_loop()
with aiomonitor.start_monitor(loop=loop):
loop.run_forever()
启动后会打印类似 Starting aiomonitor at 127.0.0.1:8080 的提示。用浏览器打开该地址,就能看到实时任务列表、挂起的协程、内存统计等。如果页面打不开,大概率是端口被占或防火墙拦截——可改用 host='0.0.0.0' 和 port=9999 显式指定。
-
aiomonitor默认绑定127.0.0.1,Docker 或远程调试时必须设host='0.0.0.0' - 它会自动注册 SIGUSR2 信号(Linux/macOS),发
kill -USR2 <pid>可触发控制台交互式 shell - 若项目用了
uvloop,需确保aiomonitor在uvloop.install()之后启动,否则监控失效
怎样从 aiomonitor 页面快速定位卡顿源头
卡顿通常表现为某个协程长时间处于 running 状态(而非 pending 或 done),或在 Tasks 列表里持续占据顶部多行。重点关注:
-
State列显示running且When时间远大于 100ms —— 这说明它正在执行同步阻塞操作 -
Stack折叠框展开后,看最底部几行是否含time.sleep()、requests.get()、json.loads()或文件读写等同步调用 -
Slow callbacks标签页会汇总所有耗时 >500ms 的回调,按耗时倒序排列,比手动翻栈更直接
示例中若看到:File "myapp.py", line 42, in fetch_data → data = json.loads(raw),就说明大 JSON 解析阻塞了事件循环——应换用 ujson 或移到 loop.run_in_executor() 中。
卡顿修复后,怎么验证 aiomonitor 不再报警
别只看页面“没红标”就认为好了。真实验证要结合两个动作:
- 在监控页持续观察
Tasks列表 30 秒以上,确认无任何running状态停留超 200ms - 用
curl http://127.0.0.1:8080/metrics获取 Prometheus 格式指标,检查aiomonitor_task_running_seconds_sum是否稳定在低位(理想是接近 0) - 若仍偶发卡顿,开启
aiomonitor的 debug 日志:logging.getLogger('aiomonitor').setLevel(logging.DEBUG),它会在终端输出每次采样时的最长运行任务详情
真正难的是那些偶发、非复现的卡顿——它们往往藏在第三方库的隐式同步调用里,比如某个 ORM 的 .save() 方法内部做了磁盘 flush,这种必须靠 aiomonitor 的连续采样才能捞出来。


















