Event loop is closed 是 Python 异步编程里很常见的错误,通常出现在 asyncio、aiohttp、playwright、selenium-wire、异步爬虫、AI Agent、FastAPI 等场景。
核心原因:
事件循环(event loop)已经被关闭,但代码还在继续调用异步任务。
一、最常见触发场景
1. 重复调用 asyncio.run()
错误示例:
import asyncio
async def test():
print("hello")
asyncio.run(test())
asyncio.run(test()) # 某些环境可能报错
尤其:
Jupyter
PyCharm Console
Flask
已经存在 loop 的环境
容易出问题。
二、正确解决方法
方法1:统一只运行一个 loop(推荐)
import asyncio
async def main():
print("hello")
if __name__ == "__main__":
asyncio.run(main())
不要到处:
asyncio.run(xx())
三、Jupyter Notebook 特殊解决方案
Jupyter 本身已经有 loop。
所以:
asyncio.run()
容易报:
RuntimeError: Event loop is closed
或者:
RuntimeError: This event loop is already running
解决:
安装:
pip install nest_asyncio
代码:
import nest_asyncio
nest_asyncio.apply()
然后:
await main()
而不是:
asyncio.run(main())
四、aiohttp 报错解决
很多人这样写:
session = aiohttp.ClientSession()
程序结束后 session 被销毁,
loop 已关闭。
正确写法:
import aiohttp
import asyncio
async def main():
async with aiohttp.ClientSession() as session:
async with session.get("https://example.com") as r:
print(await r.text())
asyncio.run(main())
必须:
使用 async with
自动关闭 session
五、Windows 常见问题(非常多)
Python 3.8+ 在 Windows 上:
默认:
ProactorEventLoop
某些库不兼容。
解决:
import asyncio
asyncio.set_event_loop_policy(
asyncio.WindowsSelectorEventLoopPolicy()
)
放最顶部。
特别是:
playwright
pyppeteer
aiodns
aiohttp
telegram bot
websocket
很常见。
六、多线程导致 loop 关闭
错误写法:
threading.Thread(target=asyncio.run, args=(main(),))
线程结束后 loop 被关闭。
正确:
def run():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(main())
loop.close()
七、Playwright 常见报错
错误:
playwright._impl._api_types.Error:
Event loop is closed!
解决:
不要混用:
sync API
async API
错误:
from playwright.sync_api import sync_playwright
又:
asyncio.run()
容易炸。
正确:
统一 async:
from playwright.async_api import async_playwright
import asyncio
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto("https://example.com")
await browser.close()
asyncio.run(main())
八、FastAPI/Uvicorn 场景
不要:
asyncio.run()
FastAPI 本身已经管理 loop。
错误:
@app.get("/")
async def index():
asyncio.run(test()) # 错
正确:
@app.get("/")
async def index():
await test()
九、彻底全面修复模板(推荐收藏)
适合大多数项目:
import asyncio
import sys
if sys.platform.startswith("win"):
asyncio.set_event_loop_policy(
asyncio.WindowsSelectorEventLoopPolicy()
)
async def main():
print("running")
if __name__ == "__main__":
try:
asyncio.run(main())
except RuntimeError:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(main())
十、如何快速定位是谁关闭了 loop
调试:
import asyncio
loop = asyncio.get_event_loop()
print(loop.is_closed())
输出:
True
说明 loop 已被提前关闭。
十一、最容易踩坑的库
下面这些最容易出现 Event loop is closed:
库 容易原因
aiohttp session没关闭
Playwright sync/async混用
pyppeteer Chromium退出
FastAPI asyncio.run
discord.py loop重复
aiogram bot关闭
selenium-wire loop冲突
websockets 连接未释放
十二、本质理解(重点)
Python 异步:
任务(Task)
↓
事件循环(Event Loop)
↓
调度执行
一旦:
loop.close()
那么:
所有 async task
await
socket
websocket
aiohttp
都会失效。
然后就报:
Event loop is closed
十三、最稳的开发建议
推荐结构:
async def main():
...
if __name__ == "__main__":
asyncio.run(main())
并且:
不要多次 run
不要手动 close
不要 sync async 混用
不要在线程共享 loop
这样基本不会再出现这个错误。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70050070/viewspace-3117835/ ,如需转载,请注明出处,否则将追究法律责任。