使用aiohttp和asyncio发起异步请求时遇RuntimeError: Event loop is closed
解决Windows下Python 3.10+ aiohttp异步请求后出现的
RuntimeError: Event loop is closed报错 我之前在Windows环境用Python 3.10跑类似的aiohttp异步请求代码时,也碰到过一模一样的报错。这个问题的根源是:Windows上Python 3.8+默认使用的Proactor事件循环,在事件循环关闭后,还有未完成的_ProactorBasePipeTransport对象在垃圾回收阶段尝试访问已关闭的循环,从而抛出这个错误。
下面给你两种可行的解决方案,优先推荐第一种:
方案一:切换到Selector事件循环策略
这是最稳定有效的解决方法,通过指定事件循环策略,替换掉默认的Proactor循环。修改后的完整代码如下:
import aiohttp import asyncio import time # 添加这两行,指定使用WindowsSelectorEventLoopPolicy asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) start_time = time.time() async def get_pokemon(session, url): async with session.get(url) as resp: pokemon = await resp.json() return pokemon['name'] async def main(): async with aiohttp.ClientSession() as session: tasks = [] for number in range(1, 151): url = f'https://pokeapi.co/api/v2/pokemon/{number}' # 用asyncio.create_task替代ensure_future,是Python 3.7+更规范的写法 tasks.append(asyncio.create_task(get_pokemon(session, url))) original_pokemon = await asyncio.gather(*tasks) for pokemon in original_pokemon: print(pokemon) asyncio.run(main()) print("--- %s seconds ---" % (time.time() - start_time))
Selector事件循环是更传统的异步IO实现,在这种批量HTTP请求的场景下,能避免Proactor循环的资源清理不及时问题。
方案二:添加短暂延迟(临时 workaround)
如果不想修改事件循环策略,可以在asyncio.run(main())之后添加一小段延迟,让事件循环的资源有足够时间完成清理。不过这个方法不如方案一稳定,仅作为临时替代:
asyncio.run(main()) time.sleep(0.1) # 给资源清理预留极短时间 print("--- %s seconds ---" % (time.time() - start_time))
内容的提问来源于stack exchange,提问作者Valerii
相关产品推荐
相关产品推荐

