🐍 告别“同步”阻塞,拥抱“异步”高并发!Flask vs FastAPI 实战笔记
摘要:还在写同步接口导致服务器卡成PPT?本文手把手带你从 Flask 迁移到 FastAPI,讲透同步与异步的底层原理,教你如何用
async/await榨干服务器性能!
大家好,我是爱摸鱼的打工仔。
最近有个粉丝私信问我:“为啥我的 Python 接口一遇到高并发就卡成 PPT?明明 CPU 占用率不高,但请求就是排队?”
我一看代码,好家伙,全是同步阻塞操作!
今天咱们就来聊聊后端开发中的“任督二脉”——同步与异步。咱们用最熟悉的 Flask 做对比,带你入坑性能炸裂的 FastAPI,顺便把原理给你盘得明明白白。
🤔 一、 为什么你的接口会“卡”?(原理篇)
在讲代码之前,咱们先讲个故事。
1. 同步(Flask 的默认模式):银行柜台
想象一下你去银行办业务。
- 同步模式:只有一个柜台开放。你进去办业务(比如查余额),柜员去查系统,这时候柜员必须等着,不能接待下一个人。如果查余额要 5 秒,后面排队的人就得干等 5 秒。
- Flask 的处境:Flask 默认是基于 WSGI 的,它是同步的。每个请求来了,就占用一个线程。如果这个请求要去查数据库(I/O 操作),线程就傻等着。人多了,线程池爆了,服务就挂了。
2. 异步(FastAPI 的模式):海底捞服务员
- 异步模式:服务员(主线程)拿着菜单(事件循环)。你点菜(发起请求),服务员记下来,转头就去厨房下单(挂起任务),然后立刻去接待下一桌客人。等厨房做好了(I/O 完成),服务员再把菜端给你。
- FastAPI 的优势:它是基于 ASGI 的,原生支持
async/await。遇到耗时的 I/O 操作(查库、调API),它会先“挂起”,腾出手来处理其他请求。
一句话总结:同步是“一条路走到黑”,异步是“东方不亮西方亮”。
⚔️ 二、 代码实战:Flask vs FastAPI
咱们来实现同一个功能:接收一个 POST 请求,模拟耗时操作,返回 JSON。
1. Flask 写法(同步)
这是大家最熟悉的配方:
# app_flask.py
from flask import Flask, request, jsonify
import time
app = Flask(__name__)
@app.route('/api/data', methods=['POST'])
def get_data():
# 1. 获取参数
data = request.get_json()
name = data.get('name')
# 2. 模拟耗时操作 (比如查数据库) - 阻塞!
# 在这 2 秒内,其他用户的请求都会被卡住
time.sleep(2)
# 3. 返回结果
return jsonify({
"code": 200,
"msg": f"Flask 处理完成: Hello {name}",
"data": None
})
if __name__ == '__main__':
# Flask 内置服务器,开发用用还行
app.run(debug=True, port=5000)
2. FastAPI 写法(异步)
来看看 FastAPI 有多优雅,顺便体验一下类型提示的爽感:
# app_fastapi.py
from fastapi import FastAPI
from pydantic import BaseModel
import asyncio
app = FastAPI()
# 1. 定义数据模型 (自动校验参数,不用手写 if not data!)
class Item(BaseModel):
name: str
price: float = 0.0
@app.post("/api/data")
async def create_item(item: Item):
# 2. 模拟异步耗时操作
# 注意:这里必须用 asyncio.sleep,不能用 time.sleep!
# asyncio.sleep 是“假睡”,它会告诉事件循环:“我去歇会儿,你先处理别人的请求”
await asyncio.sleep(2)
# 3. 直接返回字典,FastAPI 会自动转成 JSON
return {
"code": 200,
"msg": f"FastAPI 极速响应: Hello {item.name}",
"price": item.price
}
启动方式不同哦!
FastAPI 需要配合 ASGI 服务器(推荐 Uvicorn)运行,在命令行输入:
uvicorn app_fastapi:app --reload
🛠️ 三、 核心干货:如何把“同步”改为“异步”?
很多同学会问:“我有现成的 Flask 代码,怎么改成异步?”
这里有个大坑,千万别踩!
❌ 错误示范
# 千万别这么写!
@app.get("/bad")
async def bad_code():
time.sleep(2) # 错误!在 async 函数里用同步阻塞代码,会卡死整个事件循环!
return {"msg": "卡死了"}
✅ 正确姿势
要把同步接口改为异步,核心原则是:所有的 I/O 操作都要用异步库,或者扔到线程池里。
改造步骤:
- 函数定义:
def改为async def。 - 等待操作:加上
await关键字。 - 阻塞代码处理:如果必须用同步库(比如老旧的 MySQL 驱动),用
run_in_executor包装。
实战代码(模拟把同步逻辑改造为异步):
import asyncio
from fastapi import FastAPI
import time
app = FastAPI()
# 假设这是你原本的同步业务逻辑
def sync_heavy_task():
time.sleep(2)
return "任务完成"
@app.get("/async-good")
async def good_async():
# 方法一:如果是纯计算或阻塞代码,扔到线程池,别阻塞主线程
loop = asyncio.get_event_loop()
result = await loop.run_in_executor(None, sync_heavy_task)
# 方法二:如果是网络请求,用 httpx 等异步库代替 requests
# response = await client.get('...')
return {"msg": result}
💡 四、 知识点小灶(敲黑板)
为了让你在面试或者工作中显得更专业,这几个概念必须得懂:
-
WSGI vs ASGI
- WSGI:Web Server Gateway Interface,Flask/Django 用的。它是同步的,一次请求对应一个线程。
- ASGI:Asynchronous Server Gateway Interface,FastAPI 用的。它是异步的,支持高并发,还能搞 WebSocket。
-
协程
- 你可以把它理解为“轻量级线程”。开启一万个线程电脑可能卡死,但开启一万个协程对 Python 来说小菜一碟。
-
Pydantic
- FastAPI 的灵魂。它利用 Python 的类型提示(Type Hints)自动帮你做数据校验。以前你要写一堆
if not request.json.get('name'),现在直接定义个类就搞定了。
- FastAPI 的灵魂。它利用 Python 的类型提示(Type Hints)自动帮你做数据校验。以前你要写一堆
📌 五、 总结
- Flask:适合简单项目、内部工具,或者你不想学新东西的时候。生态好,插件多。
- FastAPI:强烈推荐! 性能接近 NodeJS 和 Go,自带文档(
/docs路径),代码提示极其舒服。
打工仔寄语:
技术更新迭代快,从同步到异步是 Python 后端开发的必经之路。别怕难,写两个接口试试,你会发现新大陆的!
如果觉得这篇文章对你有帮助,点个赞再走呗!我是爱摸鱼的打工仔,我们下期见!👋