Win11 Python3.10用aiohttp并发请求报Event loop is closed错误
问题说明
你实现的并发请求逻辑本身可正常工作:4个接口请求全部成功返回、结果正确收集、总耗时符合并发执行预期。抛出的RuntimeError: Event loop is closed属于Windows平台Python异步生态的已知兼容问题,不影响实际业务执行结果。
根本原因
Python 3.8+在Windows系统下默认使用ProactorEventLoop作为异步事件循环实现。当asyncio.run()执行完成、正常关闭事件循环后,aiohttp底层的网络连接管道对象在垃圾回收阶段触发析构逻辑,尝试向已经关闭的事件循环投递资源清理任务,就会触发该异常。异常出现在程序退出前的资源回收阶段,和你的业务请求逻辑无关。
可直接落地的解决方案
方案1:切换事件循环实现(优先推荐,改动最小)
在代码导入asyncio后,立刻将事件循环策略切换为Windows平台兼容的Selector实现,仅需新增1行代码,无任何业务侵入性:
import asyncio # 新增以下配置即可解决 asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) import aiohttp import time names = ["rahul"]*4 def get_tasks(session): tasks = [] for name in names: tasks.append(asyncio.create_task(session.get(url =f"https://api.agify.io?name={name}", ssl=False))) return tasks async def my_f2(): result = [] async with aiohttp.ClientSession() as session: tasks = get_tasks(session) responses = await asyncio.gather(*tasks,return_exceptions=True) for response in responses: result.append(await response.json()) return result if __name__ == "__main__": start = time.time() result = asyncio.run(my_f2()) print(result) end = time.time() print(f"Total time : {end-start}")
方案2:显式释放HTTP响应资源
原代码中读取响应JSON内容后未显式释放响应对象,会放大资源清理的时序问题,可以通过async with语法主动管理响应对象的生命周期,调整my_f2函数的响应处理段即可:
async def my_f2(): result = [] async with aiohttp.ClientSession() as session: tasks = get_tasks(session) responses = await asyncio.gather(*tasks,return_exceptions=True) for response in responses: # 显式管理响应对象生命周期,退出上下文时自动释放连接 async with response: result.append(await response.json()) return result
- 注意:该方案单独使用时在部分Python版本下仍可能抛出零星异常,和方案1搭配使用可彻底解决问题。
方案3:异常过滤(兜底方案,不推荐优先使用)
如果上述两个方案调整后仍有异常抛出,可以通过自定义异常钩子忽略该特定的无害异常,该方案会全局过滤同类异常,可能掩盖真实的事件循环错误,仅作为兜底使用:
import sys def silence_event_loop_closed_exception(exc_type, exc_val, exc_tb): if issubclass(exc_type, RuntimeError) and str(exc_val) == 'Event loop is closed': return sys.__excepthook__(exc_type, exc_val, exc_tb) sys.excepthook = silence_event_loop_closed_exception
内容的提问来源于stack exchange,提问作者Rahul Dey
相关产品推荐
相关产品推荐

