Flask 3.0 原生支持 async 路由,需搭配 ASGI 服务器(如 uvicorn)运行,禁用 flask run;同步与异步路由可共存;异步视图中须用真正异步 I/O 操作,避免阻塞事件循环。

Flask 3.0 的路由函数可以直接用 async 定义
Flask 3.0 原生支持 async 路由,不需要额外包装或中间件。只要运行在支持异步的 ASGI 服务器(如 uvicorn 或 hypercorn)上,async def 视图函数就能被正确调度执行。
关键前提是:不能用 Flask 自带的 flask run(它只启动 WSGI 开发服务器,不支持 async)。否则会报错:RuntimeWarning: Running asyncio.run() in a running event loop,甚至直接阻塞或崩溃。
- 必须用
uvicorn myapp:app启动(myapp.py中定义了app实例) -
app实例无需修改,Flask 3.0 自动识别async def视图并交由 ASGI 生命周期管理 - 同步路由和异步路由可在同一应用中混用,Flask 内部会分别处理
异步视图里调用 I/O 操作要选对方式
协程函数里不能直接调用普通同步阻塞函数(比如 requests.get()、sqlite3.connect()),否则会阻塞整个事件循环。必须用真正异步的替代方案。
- HTTP 请求:改用
httpx.AsyncClient或aiohttp.ClientSession,而不是requests - 数据库:用
asyncpg(PostgreSQL)、aiosqlite(SQLite)、或 SQLAlchemy 2.0+ 的async_engine配合await session.execute() - 文件读写:避免
open(),改用anyio.Path或aiopath;日志写入也需注意,logging默认是同步的,高并发下建议用structlog+ 异步 handler 或写入队列
示例:
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
立即学习“Python免费学习笔记(深入)”;
@app.route("/fetch")
async def fetch_data():
async with httpx.AsyncClient() as client:
resp = await client.get("https://httpbin.org/delay/1")
return resp.json()
别在 async 视图里调用 time.sleep() 或其他同步阻塞操作
time.sleep() 是纯同步阻塞,会卡住整个事件循环,导致所有并发请求停滞。这是新手最容易踩的坑。
- 要用
await asyncio.sleep(1)替代time.sleep(1) - 第三方库若没提供异步接口,又必须调用,可用
asyncio.to_thread()(Python 3.9+)把同步函数扔进线程池执行,例如:await asyncio.to_thread(json.loads, text) - 但注意:
to_thread不解决 CPU 密集型问题,只是“不卡 event loop”;真有大量计算,应考虑ProcessPoolExecutor或提前离线处理
调试时要注意 request context 在 async 环境下的生命周期
Flask 的 request 对象在 async 视图中仍是可用的,但它不是线程局部,而是协程局部(由 contextvars 维护)。这意味着你在 await 调用后仍能安全访问 request.args、request.json 等——只要没跨协程边界手动切换上下文。
- 不要在
async def里启动新线程并试图在其中读request,会抛RuntimeError: Working outside of request context - 自定义装饰器若涉及
await,需确保它不破坏request的 contextvar 传播(比如没用contextvars.copy_context()正确传递) -
g对象同样基于contextvars,可照常使用,但它的生命周期只到当前请求协程结束
复杂点在于:一旦你 mix 了 asyncio.create_task() 或后台任务,request 和 g 就不可用了——它们不随 task 自动继承。这种场景得显式传参或用独立状态管理。


















