【异步接口:Flask vs FastAPI 实战笔记】

5 阅读5分钟

🐍 告别“同步”阻塞,拥抱“异步”高并发!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 操作都要用异步库,或者扔到线程池里。

改造步骤:

  1. 函数定义def 改为 async def
  2. 等待操作:加上 await 关键字。
  3. 阻塞代码处理:如果必须用同步库(比如老旧的 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}

💡 四、 知识点小灶(敲黑板)

为了让你在面试或者工作中显得更专业,这几个概念必须得懂:

  1. WSGI vs ASGI

    • WSGI:Web Server Gateway Interface,Flask/Django 用的。它是同步的,一次请求对应一个线程。
    • ASGI:Asynchronous Server Gateway Interface,FastAPI 用的。它是异步的,支持高并发,还能搞 WebSocket。
  2. 协程

    • 你可以把它理解为“轻量级线程”。开启一万个线程电脑可能卡死,但开启一万个协程对 Python 来说小菜一碟。
  3. Pydantic

    • FastAPI 的灵魂。它利用 Python 的类型提示(Type Hints)自动帮你做数据校验。以前你要写一堆 if not request.json.get('name'),现在直接定义个类就搞定了。

📌 五、 总结

  • Flask:适合简单项目、内部工具,或者你不想学新东西的时候。生态好,插件多。
  • FastAPI强烈推荐! 性能接近 NodeJS 和 Go,自带文档(/docs 路径),代码提示极其舒服。

打工仔寄语:
技术更新迭代快,从同步到异步是 Python 后端开发的必经之路。别怕难,写两个接口试试,你会发现新大陆的!

如果觉得这篇文章对你有帮助,点个赞再走呗!我是爱摸鱼的打工仔,我们下期见!👋