Python asyncio+aiohttp在VS Code调试中残留任务问题排查
问题分析与解答
核心差异:loop.run_until_complete vs asyncio.run
asyncio.run每次执行都会创建全新的事件循环,执行完成后自动关闭循环并清理所有关联资源(包括未完成的协程、线程池实例、aiohttp连接池等),所以不会残留前次循环的任务上下文。loop.run_until_complete是复用同一个事件循环,如果get_data()内存在未彻底清理的异步资源(比如未关闭的aiohttpClientSession、未调用shutdown()的ThreadPoolExecutor、未取消的后台协程),这些资源会在循环中持续累积,反映到调试调用栈上就是残留的任务记录。
VS Code与VSCodium的调试行为差异
两者虽基于相同的debugpy调试核心,但默认配置存在区别:
- VS Code默认启用了更详细的异步任务追踪和线程上下文记录,会保留更多调试时的调用栈信息,包括未彻底回收的线程池实例、残留协程的上下文,所以你能看到
ThreadPoolExecutor栈的堆叠。 - VSCodium默认调试配置相对精简,未开启深度的异步任务追踪,即使存在资源残留,调试器也不会主动记录并展示这些栈信息,因此看起来没有复现问题。
ThreadPoolExecutor堆叠到20个栈的原因
这并非程序崩溃,而是VS Code调试器的任务追踪上限设置导致的。调试器为避免性能损耗,会限制同时显示的线程/任务栈数量,默认上限通常为20,达到后就不再新增显示,但程序本身的线程池可能仍在正常工作(或已残留)。
解决建议
- 优先使用
asyncio.run替代loop.run_until_complete的循环写法,利用其自动资源管理特性从根源避免残留问题。 - 若必须复用事件循环,在
get_data()内严格管理资源:- 用
async with ClientSession()管理aiohttp连接,确保每次请求后关闭连接池。 - 使用
ThreadPoolExecutor时,每次用完调用executor.shutdown(wait=True),或用with ThreadPoolExecutor()上下文管理器自动回收。
- 用
- 调整VS Code调试配置:在
.vscode/launch.json中添加"asyncio": {"enable": false},关闭异步任务追踪,可减少残留栈的显示。
内容的提问来源于stack exchange,提问作者banjomosh
相关产品推荐
相关产品推荐

