FastAPI
FastAPI、Django、Flask
- 重型企业级全栈项目,选Django(自带admin后台)
- 纯API服务且追求极致性能,选FastAPI
- 轻量灵活、需要高度定制或做胶水层,选Flask
核心架构与性能
| 对比维度 | Django | FastAPI | Flask |
|---|---|---|---|
| 框架定位 | 全栈重量级(内置一切) | API专用轻量级(极致性能) | 微内核核心(高度自由) |
| 接口协议 | WSGI(原生) ASGI(实验性,支持不佳) |
ASGI(底层Starlette,原生异步) | WSGI(原生) async仅为语法糖,底层不变 |
| 并发模型 | 同步阻塞(多进程/多线程) | 事件循环(单线程异步非阻塞) | 同步阻塞(多线程,受限于GIL) |
| 基准性能 | 中等(较重,启动慢) | 最高(I/O密集场景领先2~3倍) | 中等(轻量启动快,但并发能力弱) |
WSGI/ASGI
- WSGI: 标准的通信协议,同步阻塞;适合CPU密集型业务,但高并发下线程开销极大。
- ASGI: 异步非阻塞 + 事件循环,使单个线程可撑起大量并发;使Python拥有Node.js/Go那样的高并发能力,适合IO密集型(调数据库、调第三方API)的微服务。
- 语法糖: 让代码写起来更爽、读起来更优雅的简化写法,没有改变底层逻辑。
- 胶水层: 适配转换头,用来做协议转换、数据清洗、路由转发等。
开发体验与生态
| 对比维度 | Django | FastAPI | Flask |
|---|---|---|---|
| 开箱即用程度 | 极高(内置Auth、表单、中间件) | 中等(自带校验和文档,缺ORM/鉴权) | 极低(仅路由和模板,其余全手搭) |
| API文档生成 | 需集成drf-yasg等第三方库 |
自动生成Swagger/OpenAPI(零配置) | 需集成Flask-RESTX等第三方库 |
| ORM与数据库 | 强绑定自带ORM(自动迁移,跨库) | 无绑定(常配SQLAlchemy异步/SQLModel) | 无绑定(社区标配Flask-SQLAlchemy) |
| 灵活性(自由度) | 极低(Django生态强约束) | 较高(组件可自由组装) | 最高(每个组件都可随意替换) |
| 实现同等API代码量 | 最少 | 适中 | 最多(需手动处理序列化/校验) |
适用场景与选型决策
| 应用场景 | 首选框架 | 核心理由(面试话术) |
|---|---|---|
| 复杂ERP、电商主站、OA系统 | Django | Admin后台是杀手锏,内置功能避免造轮子,长期维护成本最低。 |
| 高并发对外API、微服务网关、ML模型部署 | FastAPI | 异步高性能 + 自动生成API文档 + 类型安全(Pydantic),前后端联调极快。 |
| 轻量级单体服务、快速原型验证、物联网网关 | Flask | 资源占用极低,启动速度最快,且侵入性最小,适合做胶水层。 |
| 遗留系统改造或中间件(BFF)层 | Flask | 代码透明,极易与老旧同步代码集成,改造成本最低。 |
高阶陷阱与认知深度
| 高阶知识点 | Django / Flask(同步阵营) | FastAPI(异步阵营) |
|---|---|---|
| 异步的真实性 | 异步支持基本是语法糖,底层Worker仍是同步阻塞,无法突破GIL。 | 原生异步,但必须搭配asyncpg或异步ORM才能发挥威力。 |
| 常见的性能陷阱 | 并发量受限于线程池大小,调高线程数会导致上下文切换开销剧增。 | 若误用了同步阻塞的SQLAlchemy或未配置数据库连接池,性能会直接退化到Flask水平。 |
SQLAlchemy 2.0 支持同步和异步两种方式: psycopg2(同步阻塞)、asyncpg(异步非阻塞)。
工程能力
数据库连接池
- 连接池显示参数: 最小/最大值、客户端查询超时时间、服务端兜底超时时间(杀掉慢SQL)
- 慢SQL治理与监控: 除了索引,需检查事务中的外部IO,如生成任务(提取测试点 → 生成 → 完善 → 格式化,每步都调 LLM API,总耗时可达数分钟)整体包在 in_transaction("postgres") 里。这意味着每个生成任务独占 1 个池连接长达几分钟。
- 看板数据缓存: 非必须实时的数据,考虑进程内 TTL 缓存(1~5 分钟)或 Redis 缓存
异步任务与事件循环
Q: FastAPI 的 async/await 在底层是如何通过 asyncio 事件循环调度的?如果我在路由函数里写了一个同步的 CPU 密集型计算(比如大循环),会如何影响其他并发请求?你是如何规避的?”
A: async def 路由运行在主事件循环;若直接调同步CPU密集型计算,会阻塞整个事件循环,导致该 Worker 无法处理任何其他请求,QPS 会断崖式下跌。
解决方案
- 轻度计算: 在 async 路由中,使用 loop.run_in_executor(None, sync_func) 将其委托给默认的 ThreadPoolExecutor 执行,避免阻塞。
- 重度计算(如加密/大数据聚合): 则使用 ProcessPoolExecutor 或直接解耦为独立"待处理任务表 + Celery"定时任务。
追问: 基于"待处理任务表 + Celery"定时任务,若连接池满,新进来的请求只能阻塞等待直到超时。单靠 Python 代码,如何设计一个简易的‘熔断’或‘快速失败’逻辑?
A: 从接口层的快速拒绝
- 排队阈值熔断: 接口收到请求时,先 COUNT 任务表中 status='PENDING' 的数量。如果超过设定阈值(比如 1000 条),直接返回 HTTP 429(Too Many Requests),不再往 DB 插入新任务。这本质上就是利用了 DB 作为共享计数器,实现分布式限流。
- 超时快速失败: 在 SQLAlchemy 层面设置 pool_timeout=5s,一旦获取连接超时,立刻抛出异常并返回 503,防止请求线程无限阻塞,耗尽 Tomcat/UVicorn 的工作线程。
(Agent)任务执行时服务重启,如何恢复,同时避免从头执行
核心: 恢复重跑,先查上次执行的准确结果,从断点继续跑;跳过已成功的节点,避免从头重复执行。
- 唯一任务标识,重跑时判断上次任务执行是否成功,尤其外部工具重复调用敏感时,应具备幂等性。
- checkpoint持久化至数据库,将agent任务关键节点切片化,恢复重跑或结果不满意部分重跑从指定节点继续执行。内容包括: 当前节点、阶段输入与产物、工具调用结果、后续步骤状态等。
- 状态管理机制,节点有明确的状态划分如: 待执行、执行中、执行完成、执行失败。