本节摘要:服务上线只是起点,用户一多,两件事必然发生:重复查询拖慢接口、耗时操作堵住请求。本节给出两味主药——把热点数据放进 Redis 缓存,把慢活计交给异步任务——再介绍应对超高并发的第三条路 asyncio 异步编程。性能优化的纪律是先测量再动手:不 profiling 就优化,是程序员的自我感动。
阅读完本节,你应当能够:
性能优化最大的坑是凭感觉动手。正确流程四拍:测量当前接口耗时(日志打点或压测工具);定位瓶颈——是数据库慢查询、还是 Python 计算、还是网络往返;优化短板一处;复测确认收益。轻记账的月度统计接口在账目上万条后明显变慢——测量发现每次请求都全表聚合,而这个"本月合计"一分钟内几乎不变。特征对上了:读多写少、结果可复用——教科书级的缓存场景。

Redis 是内存键值数据库,读写都在内存,比关系库快几个数量级——5.1 说的"非关系型补缓存与高吞吐场景"在此兑现:
import json, redis r = redis.Redis(host="localhost", port=6379, decode_responses=True) def month_total_cached(user_id, month): key = f"total:{user_id}:{month}" cached = r.get(key) if cached is not None: # 命中 return float(cached) total = month_total_from_db(user_id, month) # 未命中,查库计算 r.set(key, total, ex=300) # 写回缓存,五分钟过期 return total def add_record(item, amount, user_id): # 写操作要"打脏"缓存 db_add_record(item, amount, user_id) r.delete(f"total:{user_id}:{date.today().strftime('%Y-%m')}")
三个设计决定。键带用户与月份:粒度精细,别人记账不影响你的缓存。过期时间兜底:即便忘了打脏,五分钟后缓存自然失效——过期是防脏读的保险丝。写操作删除对应键:用户记一笔,本月合计的缓存立即作废,下次查询重算。读改写之间永远存在一瞬间的旧值窗口,"写后删键"是把窗口压到最小的实用折衷,一致性要求极高的场景要换成更复杂的方案(先更新库再双删等),此处建立概念即可。
导出全年账目报表要十几秒——用户点完按钮干等十秒白屏?把慢活从请求路径上摘下来:
from concurrent.futures import ThreadPoolExecutor pool = ThreadPoolExecutor(max_workers=4) @app.post("/api/export") def export(): task_id = new_task_id() pool.submit(export_job, current_user_id(), task_id) # 丢给后台线程 return jsonify({"task_id": task_id}), 202 # 立刻受理 @app.get("/api/export/status") def status(): return jsonify(check_task(current_task_id())) # 前端轮询进度
请求只做两件事:受理(返回 202 与任务号)和查进度。真正的工作在后台线程跑完,写文件、发通知。处理完立即返回,是接口响应速度的第一原则。生产规模下线程池换成任务队列(如 Celery 加 Redis),模型不变:提交、执行、查询三段式。
线程池是"开更多工人",asyncio 是"一个工人不停手":
import asyncio async def fetch_url(url): reader, writer = await asyncio.open_connection(url, 80) # await 处等待时,事件循环去服务其他任务——单线程并发上千连接 ...
它的高效来自不等:发起网络请求后不傻等回复,转身处理下一个任务,回复到了再回头。所以 asyncio 的甜区是 I/O 密集(大量网络调用、磁盘读写);CPU 密集任务(图片处理、大数据计算)它帮不上忙——计算时事件循环也被占死,"伪异步"反而添乱。另外整个调用链要全是异步写法,中途插一个同步阻塞调用就前功尽弃。本书项目并发量有限,用线程池足矣;asyncio 记住"什么时候该想到它",比现在就精通它更重要。
给月度统计接口装上缓存,用压测脚本对比:缓存前每秒处理请求数与缓存后差几倍(通常十倍起步)。变式一:把过期时间调成 300 秒与 3 秒各测一次命中率,体会"过期太短缓存形同虚设、太长脏读窗口拉大"的权衡。变式二:把报表导出改成异步三段式,前端加一个进度条轮询——用户体验的改善肉眼可见。
性能有了预案,最后一课是底线:安全。下一节把全书散落的安全点收拢成一张上线自检清单。