在开发高性能 Web 应用时,我们常常面临这样的困惑:明明硬件配置不断升级,可系统在高并发场景下还是显得力不从心。是框架选择有误?还是代码架构存在短板?今天我们就以 FastAPI 为切入点,深入剖析异步编程的核心逻辑,揭开并发处理的神秘面纱,让你的 API 服务在高负载下依然能保持丝滑体验。
在 FastAPI 中定义路由函数时,我们首先面临一个关键选择:用def
还是async def
?这里有套简单直接的决策准则:
如果使用的库明确要求通过await
调用,比如异步数据库驱动或 HTTP 客户端,那么路由函数必须用async def
定义:
python
from fastapi import FastAPI
app = FastAPI()
# 注意这里的async def声明
@app.get("/async-data")
async def read_async_data():
# 假设some_async_library是异步库
results = await some_async_library.fetch_data()
return {"data": results}
关键点:await
只能在async def
定义的函数内使用,这是 Python 异步语法的硬性规定。
目前大多数数据库库(如传统的 SQLAlchemy)还是同步接口,这时保持普通函数定义即可:
python
@app.get("/sync-data")
def read_sync_data():
# 调用同步库
results = sqlalchemy_session.query(Model).all()
return {"data": results}
FastAPI 会自动将同步函数放入线程池执行,避免阻塞主线程。
await
语句,但如果应用需要处理大量 I/O 操作,建议用async def
def
def
和async def
,框架会智能处理不同类型的函数实践经验:在微服务架构中,凡是涉及网络调用(HTTP/RPC)、文件操作或数据库交互的接口,推荐使用
async def
定义,性能提升显著。
异步编程的核心在于让程序在等待 I/O 操作时不阻塞。想象我们在下载大文件时,传统同步方式会让整个程序卡住,而异步模式下:
这种机制特别适合处理 I/O 密集型操作,包括:
就像和心仪的人去买汉堡:
这里的 "计算机"(我们)在等待汉堡制作时,能同时处理 "聊天" 任务,CPU 利用率最大化。这就是异步并发的核心:通过任务切换避免等待时间浪费。
假设每个收银员同时也是厨师:
这种模式下,"计算机"(我们)必须专注等待,无法同时处理其他任务,就像 CPU 核心被完全占用。这就是同步并行的特点:多任务同时执行,但每个任务都需要独占资源。
维度 | 并发(异步) | 并行(同步) |
---|---|---|
资源利用 | 单线程处理多任务,CPU 利用率高 | 多线程 / 多进程,资源消耗大 |
适用场景 | I/O 密集型操作(网络、磁盘) | CPU 密集型操作(计算、加密) |
典型案例 | Web 服务、API 网关 | 图像渲染、机器学习训练 |
Python 从 3.5 + 引入的异步语法非常直观:
python
# 定义异步函数
async def fetch_data():
# 模拟异步操作,实际项目中替换为真实I/O操作
await asyncio.sleep(0.1) # 模拟网络请求延迟
return {"message": "Data fetched"}
# 调用异步函数
async def main():
result = await fetch_data()
print(result)
# 运行异步程序
if __name__ == "__main__":
import asyncio
asyncio.run(main())
python
from fastapi import FastAPI
import aiohttp # 异步HTTP客户端
app = FastAPI()
# 定义依赖项
async def get_http_client():
async with aiohttp.ClientSession() as session:
yield session
# 异步路由函数
@app.get("/external-api")
async def call_external_api(session: aiohttp.ClientSession = Depends(get_http_client)):
# 异步调用外部API
async with session.get("https://api.example.com/data") as response:
data = await response.json()
return {"external_data": data}
# 同步路由函数(用于对比)
@app.get("/sync-task")
def process_sync_task():
# 模拟耗时的同步操作
import time
time.sleep(0.5) # 阻塞当前线程
return {"status": "Task completed synchronously"}
async def
定义的函数返回的是协程对象,它具有以下特点:
await
处暂停执行这与 Go 语言的 Goroutines 非常相似,但 Python 的协程基于事件循环机制,更适合处理海量并发连接。
当我们定义普通函数def
时,FastAPI 会做一件很聪明的事:将同步函数放入外部线程池执行,然后通过await
等待结果。这意味着:
FastAPI 完美支持同步与异步代码混合使用:
python
from fastapi import FastAPI
import time
import asyncio
app = FastAPI()
# 同步工具函数
def heavy_compute(x: int, y: int) -> int:
# 模拟CPU密集型计算
time.sleep(0.1) # 这里实际应使用线程池或进程池
return x + y
# 异步路由函数中调用同步函数
@app.get("/hybrid-task")
async def hybrid_operation():
# 在异步函数中调用同步函数
# 注意:实际项目中应使用asyncio.to_thread()
result = await asyncio.get_event_loop().run_in_executor(
None, lambda: heavy_compute(100, 200)
)
return {"result": result}
通过本文,我们深入探讨了 FastAPI 异步编程的核心要点:
async def
与def
的选择准则async/await
语法的实际应用如果本文对你有帮助,别忘了点赞收藏,关注我,一起探索更高效的开发方式~