Flask 3.0 的 async 路由必须运行在 ASGI 服务器(如 uvicorn)上,不能用 flask run;async 路由内须使用异步 I/O(如 httpx.AsyncClient、await asyncio.sleep),禁用 requests、time.sleep 等同步操作。

Flask 3.0 的 async 路由必须运行在异步服务器上
Flask 3.0 原生支持 async def 路由,但**不等于它会自动异步执行**。如果你用 flask run 启动,默认的 Werkzeug 开发服务器仍是同步的——此时定义 async def 路由会直接报错:RuntimeError: Attempted to use a sync app with async route。
必须换用真正支持 ASGI 的服务器,比如 uvicorn 或 hypercorn:
pip install uvicorn
启动方式也得改:
uvicorn myapp:app --reload
其中 myapp:app 是模块名和 Flask 实例名,不能用 flask run。
立即学习“Python免费学习笔记(深入)”;
async 路由里不能混用阻塞式 I/O 操作
写 async def 路由只是语法层面允许异步,不代表函数体内所有代码都自动变非阻塞。常见踩坑点:
Uvicorn 0.52.1 是 Python ASGI Web 服务器,提供异步应用服务及 WebSocket 支持,常用于 FastAPI、Starlette 等应用的开发和部署。本下载为官方 PyPI 通用 wheel 包,可使用 pip 安装,并由包管理器处理所需依赖。
-
requests.get()是同步阻塞调用,会卡住整个事件循环,必须换成httpx.AsyncClient或aiohttp -
time.sleep(1)会阻塞,得换成await asyncio.sleep(1) - 数据库操作:SQLAlchemy 2.0+ 提供
async_session,但需搭配asyncpg或aiomysql等异步驱动,sqlite不支持异步
示例(正确):
import httpx<br>from flask import Flask<br><br>app = Flask(__name__)<br><br>@app.route("/api")<br>async def api():<br> async with httpx.AsyncClient() as client:<br> resp = await client.get("https://httpbin.org/json")<br> return resp.json()
同步路由和异步路由可以共存,但不能共享阻塞资源
同一个 Flask 应用里,def 和 async def 路由可以并存,Flask 会分别调度。但要注意:
- 全局变量、普通类实例、未加锁的缓存(如
dict)在异步上下文中可能被并发读写,引发状态错乱 - 不要在异步路由里调用同步函数并指望它“变快”——它只会让事件循环等得更久
- 日志记录建议用
structlog或带异步 handler 的logging配置,避免logging.info()在高并发下成为瓶颈
调试时别依赖 print,要抓真正的协程生命周期
print() 在 async 路由里能输出,但容易掩盖执行顺序问题。比如:
@app.route("/test")<br>async def test():<br> print("start")<br> await asyncio.sleep(0.1)<br> print("end")<br> return "done"
你以为输出是线性顺序,但在并发请求下,“start”和“end”可能交错出现,且无法反映哪个请求对应哪对输出。更可靠的方式是打唯一 trace ID:
import asyncio, uuid<br><br>@app.route("/test")<br>async def test():<br> req_id = str(uuid.uuid4())[:8]<br> print(f"[{req_id}] start")<br> await asyncio.sleep(0.1)<br> print(f"[{req_id}] end")<br> return "done"
异步调试的关键不是“有没有输出”,而是“谁在什么时候占用了事件循环”。真正卡住的地方,往往藏在你没 await 的地方。


















