flask 2.0 的 async 视图仅在 asgi 服务器(如 uvicorn)下真正异步;使用 flask run、gunicorn 默认 wsgi 模式会退化为同步或报错,且钩子函数不支持 async,i/o 必须全链路异步。

Flask 2.0 的 async 视图只有在 ASGI 服务器(如 Uvicorn)下才真正异步;用 flask run 或 Gunicorn 默认 WSGI 模式会退化为同步,甚至直接报错。
async 视图函数必须搭配 ASGI 服务器启动
写了 async def 不等于自动异步——Werkzeug 的开发服务器(app.run())根本不支持 asyncio 事件循环,启动时会抛 RuntimeError: There is no current event loop。Uvicorn 或 Hypercorn 才是正确载体。
- 正确启动方式:
uvicorn main:app(假设入口模块是main.py,Flask 实例名为app) - 错误方式:
flask run、python main.py、gunicorn main:app(默认 WSGI) - 若坚持用 Gunicorn,需加
--worker-class uvicorn.workers.UvicornWorker,且仍要确保安装uvicorn
视图内所有 I/O 调用必须是原生异步库
混用 requests.get() 这类同步阻塞调用,会让整个 Uvicorn worker 卡死:一个请求阻塞,所有并发协程都等它释放事件循环。
- HTTP 请求替代方案:
aiohttp.ClientSession、httpx.AsyncClient - 数据库操作必须用异步驱动:
asyncpg(PostgreSQL)、aiomysql(MySQL),配合 SQLAlchemy 2.0+ 的create_async_engine和AsyncSession - 绝对不能用:
requests、sqlite3、psycopg2、db.session(Flask-SQLAlchemy 同步实例)
Flask 钩子函数(before_request 等)不支持 async
即使你把 @before_request 写成 async def,Flask 也不会 await 它——只会把它当普通函数调用,导致协程对象未被消费,可能引发 RuntimeWarning: coroutine 'xxx' was never awaited,甚至内存缓慢增长。
- 所有钩子函数必须保持同步写法
- 需要异步初始化的数据(如从缓存预加载配置),应放在应用启动时用
asyncio.run()显式执行,或改用中间件 + ASGI 生命周期事件(如 Uvicorn 的on_startup) -
g、request、session在 async 视图中可用,但它们的作用域仅限当前请求协程,不会跨await边界泄漏
数据库连接池和线程模型必须显式隔离
异步 ORM 不是“开个开关”,而是整套资源调度逻辑的切换。混用同步/异步连接池会导致连接泄漏、超时、事务不一致。
- 创建引擎时必须指定异步 URL:
postgresql+asyncpg://...,不能是postgresql://... - 连接池类型要匹配:
poolclass=NullPool(推荐)或AsyncAdaptedQueuePool,避免与同步QueuePool混淆 - 不要试图在 async 视图里用
loop.run_in_executor包装同步 DB 调用——这会绕过异步优势,还引入线程竞争风险
最易被忽略的一点:ASGI 服务器的并发能力取决于单个 worker 的事件循环吞吐,而不是进程数。一个 Uvicorn worker 能轻松处理数千并发请求,但前提是里面没有一个 time.sleep(1) 或 requests.get() ——这种代码在 async 上下文里比在同步里更危险,因为它表面无害,实则全局卡死。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











