Python 3.10.5使用aiohttp执行异步网络请求触发RuntimeError: Event loop is closed错误的解决方法求助
Hey, I've dealt with this exact issue before when working with Python 3.10 and aiohttp on Windows! Let's walk through what's causing this and how to fix it.
The Problem
You've written a valid async HTTP request script using aiohttp, but when you run it, you get a RuntimeError: Event loop is closed exception from the Proactor event loop. Here's your code for reference:
#!/usr/bin/python # coding=utf-8 import asyncio import aiohttp async def http_request(url, session): async with session.get(url) as response: return await response.text() async def get_results(tasks): result = await asyncio.gather(*tasks) return result async def main(): async with aiohttp.ClientSession() as session: tasks = [http_request(f"https://httpbin.org/delay/1?seq={x}", session) for x in range(3)] return await get_results(tasks) if __name__ == '__main__': results = asyncio.run(main(), debug=False) for x in results: print(x)
And the error you're seeing:
Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x000001B9B9886950> Traceback (most recent call last): File "C:\Users\Administrator\AppData\Local\Programs\Python\Python310\lib\asyncio\proactor_events.py", line 116, in __del__ self.close() File "C:\Users\Administrator\AppData\Local\Programs\Python\Python310\lib\asyncio\proactor_events.py", line 108, in close self._loop.call_soon(self._call_connection_lost, None) File "C:\Users\Administrator\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 750, in call_soon self._check_closed() File "C:\Users\Administrator\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 515, in _check_closed raise RuntimeError('Event loop is closed') RuntimeError: Event loop is closed
What's Causing This?
On Windows, Python 3.10 uses the ProactorEventLoop by default. When asyncio.run() finishes executing your main coroutine, it immediately closes the event loop. However, aiohttp's ClientSession has background cleanup tasks (like closing connections) that haven't completed yet. These tasks try to run against the already closed loop, triggering the error.
Solutions
Here are three reliable ways to fix this:
1. Force the SelectorEventLoop (Quick Workaround)
Explicitly set the event loop policy to use WindowsSelectorEventLoopPolicy instead of the default Proactor loop. Add this code right after your imports:
from asyncio import WindowsSelectorEventLoopPolicy asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy())
Your updated script will look like this:
#!/usr/bin/python # coding=utf-8 import asyncio from asyncio import WindowsSelectorEventLoopPolicy import aiohttp asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy()) async def http_request(url, session): async with session.get(url) as response: return await response.text() async def get_results(tasks): result = await asyncio.gather(*tasks) return result async def main(): async with aiohttp.ClientSession() as session: tasks = [http_request(f"https://httpbin.org/delay/1?seq={x}", session) for x in range(3)] return await get_results(tasks) if __name__ == '__main__': results = asyncio.run(main(), debug=False) for x in results: print(x)
This bypasses the Proactor loop's cleanup issues entirely.
2. Upgrade aiohttp (Permanent Fix)
The aiohttp team fixed this specific bug in version 3.8.2. Since you're on 3.8.1, just upgrade to the latest compatible version:
pip install --upgrade aiohttp
After upgrading, your original code should work without any changes. This is the best long-term solution.
3. Manually Manage the Event Loop
If you want full control over the loop lifecycle, replace asyncio.run() with manual loop setup and cleanup. This ensures all pending tasks finish before closing the loop:
if __name__ == '__main__': loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) try: results = loop.run_until_complete(main()) for x in results: print(x) finally: # Clean up async generators and pending tasks loop.run_until_complete(loop.shutdown_asyncgens()) loop.close()
This method gives the loop time to finish any background cleanup tasks before shutting down.
Which Should You Choose?
- Upgrade aiohttp: Preferred if you can update dependencies, as it fixes the root cause.
- SelectorEventLoop: Quickest fix if you can't upgrade.
- Manual loop management: Best for advanced use cases where you need full control over the event loop.
内容的提问来源于stack exchange,提问作者ikool




