同步、异步与并发
先理解“等待”
后端经常在等数据库、等其他服务、等磁盘。异步允许程序在一次等待期间处理其他可以进行的事情。
可以想象你烧水时顺便洗杯子。烧水总耗时没有因此缩短,但你利用了等待时间。CPU 密集计算则像持续做一道数学题,仅加上 async 不会自动让计算更快。
选 def 还是 async def
| 调用的工具 | 常见选择 |
|---|---|
| 同步数据库接口、同步网络请求 | 普通 def 路由,或明确转移阻塞工作 |
支持 await 的异步数据库/网络工具 | async def 路由并使用 await |
| 很轻的纯计算、组装字典 | 两者都可,保持简单一致 |
| 大量 CPU 计算 | 考虑进程、任务队列或专门计算服务 |
FastAPI 调用普通 def 路由和普通 def 依赖时,会放到外部线程池执行。你在 async def 中直接调用自己写的普通辅助函数时,不会自动得到同样的线程池转移。官方同步与异步说明
完整示例:异步等待
python
import asyncio
from fastapi import FastAPI
app = FastAPI()
@app.get("/wait")
async def wait_example():
await asyncio.sleep(1)
return {"message": "等待完成"}await asyncio.sleep(1) 在等待期间让出执行机会。它是为了演示等待,真实业务不是靠 sleep 提升性能。
容易出现的阻塞错误
python
# 错误用法的语法片段
# @app.get("/bad")
# async def bad():
# time.sleep(5) # 同步阻塞,可能卡住事件循环
# return {"ok": True}同样,不要在异步接口中直接调用耗时的同步 HTTP 请求、同步数据库查询或长时间计算,误以为 async def 会自动处理它们。
异步 HTTP 请求示例
追加到本章完整示例,需安装 httpx:
python
import httpx
@app.get("/external-example")
async def external_example():
async with httpx.AsyncClient(timeout=5.0) as client:
response = await client.get("https://example.com")
response.raise_for_status()
return {"upstream_status": response.status_code}这里使用固定 URL 展示异步调用;真实项目还需要处理超时与上游失败,频繁调用时可以在应用生命周期中复用客户端。async with 类似 with,用于需要异步清理的资源。HTTPX 异步客户端说明
别把并发与并行混为一谈
并发是让多个任务交替推进;并行是同时执行多个任务。异步主要改善等待场景下的并发。线程、进程、异步是不同工具,适用条件不同。
记忆方法:是否写 async def,取决于你调用的工具是否提供真正的异步操作。
本章练习
解释:为什么在异步接口里执行 time.sleep(5) 与 await asyncio.sleep(5) 的影响不同?
过关标准:不再认为“所有函数加上 async 就会更快”。