Flask 2.0+ 的 async 视图需用 ASGI 服务器(如 Uvicorn)启动才真正异步;WSGI 下会报错或退化为同步,且必须全程使用异步库(如 aiohttp、asyncpg),禁用 requests 等阻塞调用。

Flask 2.0+ 的 async 视图函数怎么写才真正生效
Flask 2.0+ 原生支持 async 视图,但**不是写了 async def 就自动异步**——它只在使用支持异步的 ASGI 服务器(如 Uvicorn 或 Hypercorn)时才走 asyncio 事件循环;用传统 flask run(基于 Werkzeug 的 WSGI 服务器)会直接报错或退化为同步执行。
- 必须用
Uvicorn启动:例如uvicorn main:app,而非flask run -
app.run()不支持异步,调用会抛RuntimeError: There is no current event loop - 视图内调用的协程函数(如
await aiohttp.get(...))必须是真正的异步库,不能混用requests等阻塞调用 - Flask 的上下文(
request、g、session)在 async 视图中可用,但仅限当前请求生命周期,不跨await边界泄漏
常见错误:在 async 视图里调用 requests.get 导致整个服务卡死
这是最典型的“伪异步”陷阱。WSGI 模式下混用阻塞 IO 已经很危险,ASGI 下更严重:一个 requests.get 会阻塞整个事件循环,所有并发请求都排队等待。
- 正确替代方案:用
aiohttp、httpx.AsyncClient或asyncpg等原生异步库 - 若必须用同步库(如某些 SDK),需用
loop.run_in_executor包装,但会失去轻量优势,且线程池大小需谨慎控制 - 错误示例:
requests.get("https://api.example.com")—— 这行代码会让整个 Uvicorn worker 暂停响应其他请求
before_request 和 after_request 能否异步?
不能。Flask 的钩子函数(before_request、after_request、teardown_request)目前仍为同步接口,即使你定义成 async def,Flask 也不会 await 它,而是当作普通函数调用,导致协程对象未被消费,可能引发警告甚至内存泄漏。
- 解决方案:把异步逻辑收进视图内部,或用中间件(ASGI middleware)替代钩子
- 如果一定要复用预处理逻辑,可封装为普通函数,在 async 视图开头
await一个专门的异步 helper - 注意
g对象在 async 视图中是线程/协程局部的,但钩子本身不参与 await,所以不要指望在before_request里设g.data = await fetch()
数据库操作怎么配才不拖慢 async 视图
用 SQLAlchemy 默认是同步 ORM,直接 session.query(...).all() 会阻塞事件循环。Flask 本身不提供异步 ORM 支持,得靠生态配合。
立即学习“Python免费学习笔记(深入)”;
- 推荐组合:
SQLAlchemy 2.0++async_engine+AsyncSession,搭配asyncpg(PostgreSQL)或aiomysql(MySQL) - 不能混用:
db.session(Flask-SQLAlchemy 的同步实例)不能在 async 视图里直接用 - 连接池要显式配置为异步:例如
create_async_engine("postgresql+asyncpg://...", poolclass=NullPool),避免与同步池混淆 - 简单读取场景可考虑
aiosqlite,但注意它底层仍是线程池封装,并非真异步磁盘 IO
异步视图真正起效的前提是整条链路都异步:从服务器、HTTP 客户端、数据库驱动到业务逻辑。任何一个环节掉回同步,就会成为瓶颈。很多人卡在“写了 async 却没提速”,问题往往出在没意识到 requests 或 sqlite3 这类默认同步组件的存在。










