注:本文是python的学习笔记;不是教程!不是教程!内容可能有所疏漏,欢迎交流指正。
Django 是一个成熟的、全功能 Python Web 框架,遵循"电池已包含"的理念,提供了构建 Web 应用所需的几乎所有组件。
核心特点:
适用场景:
FastAPI 是一个现代的高性能 Web 框架,专为 API 开发而设计,以速度快、代码简洁和自动生成 API 文档为特色。
核心特点:
适用场景:
Django 采用 MVT (Model-View-Template) 架构
架构组件详解:
Model(模型层)
View(视图层)
Template(模板层)
请求处理流程:
用户请求 → URL 路由 → 视图函数 → 模型交互 → 模板渲染 → 响应
Django 的主要组件
ORM:对象关系映射系统,处理数据库交互
URL 分发器::将 URL 模式映射到视图函数
模板系统:用于生成 HTML
表单处理:处理用户输入和验证
Admin 后台:自动生成管理界面
中间件:处理请求和响应的钩子系统
FastAPI 建立在 Starlette 和 Pydantic 之上
核心依赖解析:
Starlette
Pydantic
请求处理流程:
用户请求 → 路由匹配 → 依赖注入 → 路径操作函数 → 响应序列化 → 响应
FastAPI 的主要组件
Starlette:提供 ASGI 服务器支持和基础 Web 功能
Pydantic:提供数据验证和序列化
依赖注入系统:管理组件依赖
OpenAPI:自动生成 API 文档
同步执行是传统的程序执行模式:
顺序执行:代码按照编写顺序逐行执行,每一行代码必须完成后才能执行下一行
阻塞操作:当程序遇到 I/O 操作(如网络请求、文件读写、数据库查询)时,整个线程会停止并等待操作完成
资源利用率低:等待 I/O 时,CPU 实际上是空闲的,线程/进程资源被占用但无法处理其他任务
# Django 视图示例 - 同步模式
def user_profile(request, user_id):
# 数据库查询会阻塞线程, 直到查询完成
user = User.objects.get(id=user_id)
# 当前线程被阻塞 无法处理其他请求, 直到上一步执行完成得到结果(或失败)再继续执行后续代码
return render(request, 'profile.html', {'user': user})
Django 默认使用 WSGI (Web Server Gateway Interface) 服务器接口,采用同步执行模型:
同步模型的优缺点:
优点:
缺点:
异步执行是一种现代的程序执行模式,允许程序在等待I/O操作时继续执行其他任务:
非阻塞执行:遇到I/O操作时不等待,立即切换执行其他可用任务
事件循环:核心机制是一个事件循环,管理所有未完成的任务
协程:可以暂停和恢复的特殊函数,是异步编程的基本单位
协程的本质
协程(Coroutine)是一种可以暂停和恢复的特殊函数,具有以下特点:
可暂停执行:协程可以在执行过程中暂停,并在之后恢复
保存执行状态:暂停时,协程的本地变量和执行状态会被保存
协作式多任务:协程自己决定何时让出控制权(使用 await)
# FastAPI 路径操作函数 - 异步模式
@app.get("/users/{user_id}")
async def get_user(user_id: int):
# 异步数据库查询,不会阻塞线程
user = await database.query(f"SELECT * FROM users WHERE id = {user_id}")
# await 暂停当前协程(函数),让出控制权给事件循环,允许处理其他请求
return {"user": user}
FastAPI 使用 ASGI (Asynchronous Server Gateway Interface) 服务器接口,支持异步执行:
异步模型的优缺点:
优点:
缺点:
接收请求:WSGI 服务器接收 HTTP 请求
中间件处理:请求预处理(身份验证、会话等)
URL 解析:匹配 URL 与视图函数
视图执行:执行视图函数,可能涉及:
模板渲染:生成 HTML 响应
中间件后处理:响应后处理
返回响应:将响应发送回客户端
接收请求:ASGI 服务器接收 HTTP 请求
路由匹配:识别匹配的路径操作函数
参数解析与验证:
依赖注入:解析和注入依赖项
执行路径操作函数:处理请求逻辑
响应处理:
返回响应:将响应发送回客户端
# Django ORM 示例
from django.db import models
class User(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField(unique=True)
# 数据查询
users = User.objects.filter(name__startswith="张").order_by("email")
Django ORM 特点:
完整的 ORM 系统,处理关系型数据库
迁移系统,自动生成数据库 schema
丰富的查询 API
关系处理(一对一、一对多、多对多)
同步操作,不支持原生异步
FastAPI 没有内置 ORM,通常使用以下方案:
SQLAlchemy
# 使用 SQLAlchemy 的同步版本
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
name = Column(String)
email = Column(String)
# 使用 SQLAlchemy 异步版本
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
async def get_user(user_id: int):
async with AsyncSession(engine) as session:
result = await session.execute(select(User).where(User.id == user_id))
return result.scalars().first()
Tortoise ORM (异步 ORM)
from tortoise import Model, fields
class User(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=255)
email = fields.CharField(max_length=255)
# 异步查询
user = await User.filter(name__startswith="张").first()
FastAPI 数据库处理特点
灵活选择 ORM 或直接使用数据库驱动
支持异步数据库操作
与 Pydantic 模型无缝集成
成熟稳定,适合复杂应用
同步执行模型限制了高并发性能
使用多进程/多线程扩展(如 Gunicorn)
对于 I/O 密集型操作效率较低
内置缓存系统,提高性能
性能优势:
性能限制:
并发处理策略:
Django 3.1+ 开始支持 ASGI,但大部分功能仍是同步的
# Django 中使用有限的异步支持
async def my_view(request):
# 可以使用异步操作,但与 ORM 等同步组件交互仍有限制
await asyncio.sleep(1)
return HttpResponse("Hello")
极高的性能,接近 Node.js 和 Go
异步执行模型,高效处理并发
单线程处理多请求,减少资源消耗
基于 Uvicorn/Starlette 的高效 ASGI 服务器
适合高 I/O 场景(如微服务、API)
性能优势:
性能测试数据:
并发处理优势:
FastAPI 性能优势示例
@app.get("/items/")
async def read_items():
# 多个异步 I/O 操作可以并发执行
results = await asyncio.gather(
fetch_from_database(),
call_external_api(),
send_notification()
)
return {"results": results}
# urls.py
from django.urls import path
from . import views
urlpatterns = [
path('users//' , views.user_detail),
path('users/', views.user_list),
]
# views.py
def user_detail(request, user_id):
if request.method == 'GET':
# 处理 GET 请求
elif request.method == 'POST':
# 处理 POST 请求
# ...
Django 路由特点
集中式 URL 配置
基于正则表达式的路由匹配
手动处理 HTTP 方法分发
请求参数需手动解析和验证
from fastapi import FastAPI, Path, Query, Body
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
name: str
email: str
@app.get("/users/{user_id}")
async def get_user(
user_id: int = Path(..., gt=0),
q: str = Query(None, max_length=50)
):
return {"user_id": user_id, "query": q}
@app.post("/users/")
async def create_user(user: User):
return user
FastAPI 路由特点
装饰器定义路由
自动 HTTP 方法分发
自动参数解析和类型验证
基于类型注解的参数处理
OpenAPI 文档自动生成
中间件特点:
常用中间件:
# Django 中间件示例
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# 请求前处理
print("处理请求前")
response = self.get_response(request)
# 响应后处理
print("处理响应后")
return response
Django 使用类似洋葱模型的中间件系统
中间件按序执行
全局应用于所有请求
处理认证、会话、安全等横切关注点
依赖注入优势:
依赖注入应用:
from fastapi import Depends, FastAPI, HTTPException
app = FastAPI()
async def verify_token(token: str):
if token != "valid_token":
raise HTTPException(status_code=401)
return token
async def get_current_user(token: str = Depends(verify_token)):
return {"user": "current_user"}
@app.get("/users/me")
async def read_users_me(current_user: dict = Depends(get_current_user)):
return current_user
FastAPI 依赖注入系统
可重用、可嵌套的依赖项
声明式依赖管理
范围控制(请求级、应用级)
自动处理依赖解析顺序
测试友好,易于模拟依赖
<!-- Django 模板示例 -->
{% extends "base.html" %}
{% block content %}
<h1>{{ user.name }}</h1>
<ul>
{% for post in posts %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
{% endblock %}
传统服务端渲染:
现代前端集成:
FastAPI 主要关注 API 开发,前端渲染选项:
Jinja2 模板 (需要额外安装)
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.get("/items/{id}")
async def read_item(request: Request, id: str):
return templates.TemplateResponse(
"item.html", {"request": request, "id": id}
)
与前端框架集成
# FastAPI 提供 API,前端框架消费 API
@app.get("/api/users")
async def get_users():
users = await db.fetch_all("SELECT * FROM users")
return users # 自动转为 JSON
API优先设计:
模板支持:
内置安全机制:
认证和授权:
Django 安全示例
# Django 内置认证系统
from django.contrib.auth.decorators import login_required
@login_required
def profile_view(request):
# 只有登录用户可访问
return render(request, 'profile.html')
现代安全实践:
安全工具集成:
FastAPI 安全示例
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/users/me")
async def read_users_me(token: str = Depends(oauth2_scheme)):
user = get_user_from_token(token)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials"
)
return user
大量第三方应用 (Django REST Framework, Django Channels 等)
插件系统
成熟的社区支持
完整的文档和教程
企业级支持
与 Python 异步生态系统集成
扩展库较少但增长迅速
简单的扩展机制
活跃的社区
与现代开发工具集成(Docker, CI/CD 等)
内容管理系统
大型企业应用
需要管理后台的应用
数据库密集型应用
传统的服务器渲染网站
需要快速开发完整应用的场景
微服务架构
高性能 API 开发
实时应用(WebSocket)
数据科学/机器学习 API
前后端分离架构
高并发、I/O 密集型应用
全功能框架,提供完整解决方案
强大的 ORM 和管理后台
丰富的生态系统和插件
完善的文档和社区支持
稳定性和可维护性
卓越的性能和并发处理能力
异步支持,高效处理 I/O 密集型任务
现代 Python 特性(类型注解、异步)
自动 API 文档生成
简洁的代码风格
选择 Django 如果:
选择 FastAPI 如果:
混合使用:
WSGI 是 Python Web 应用与 Web 服务器之间的标准接口
基本工作原理
def wsgi_application(environ, start_response):
# environ: 包含请求信息的字典
# start_response: 用于发送响应状态和头部的回调函数
status = '200 OK'
headers = [('Content-Type', 'text/plain')]
start_response(status, headers)
# 返回响应体(必须是可迭代对象)
return [b'Hello, World!']
同步处理模型
一个请求由一个线程/进程处理
处理过程中,该线程/进程被占用直到请求完成
多个并发请求需要多个线程/进程
流程图
# 客户端请求 → Web服务器 → WSGI服务器 → WSGI应用(调用一次)→ 响应
ASGI 是 WSGI 的异步演进,支持 WebSocket 等长连接协议
基本工作原理
async def asgi_application(scope, receive, send):
# scope: 包含连接类型和请求信息的字典
# receive: 异步函数,用于接收消息
# send: 异步函数,用于发送消息
if scope['type'] == 'http':
# 处理 HTTP 请求
message = await receive() # 接收请求
# 发送响应
await send({
'type': 'http.response.start',
'status': 200,
'headers': [(b'content-type', b'text/plain')],
})
await send({
'type': 'http.response.body',
'body': b'Hello, World!',
})
异步处理模型
单个进程可以同时处理多个请求
基于事件循环和协程
I/O 操作不会阻塞整个服务器
流程图
# 客户端请求 → Web服务器 → ASGI服务器 → ASGI应用(可能多次调用)→ 响应
Gunicorn (Green Unicorn)
Gunicorn 是一个 WSGI HTTP 服务器,适用于 Django:
进程与线程配置
# 启动 4 个工作进程
gunicorn myapp.wsgi:application --workers=4
# 每个工作进程有 2 个线程
gunicorn myapp.wsgi:application --workers=4 --threads=2
工作原理
主进程接收请求并分发给工作进程
每个工作进程独立处理分配给它的请求
工作进程崩溃时,主进程会重启它
内部架构
主进程(Master)
│
├── 工作进程 1(Worker)── 线程 1
│ └── 线程 2
│
├── 工作进程 2(Worker)── 线程 1
│ └── 线程 2
│
└── ...
uWSGI
uWSGI 是另一个流行的 WSGI 服务器:
进程与线程配置
# uwsgi.ini 配置文件
[uwsgi]
processes = 4 # 工作进程数
threads = 2 # 每个进程的线程数
高级特性
内置负载均衡
进程监控和自动恢复
内存优化
Uvicorn
Uvicorn 是一个基于 uvloop 和 httptools 的 ASGI 服务器:
进程模型配置
# 单进程模式
uvicorn app:app
# 多进程模式(使用 Gunicorn 作为进程管理器)
gunicorn app:app -w 4 -k uvicorn.workers.UvicornWorker
内部架构
Uvicorn 进程
│
└── 事件循环
│
├── 协程 1(处理请求 A)
│
├── 协程 2(处理请求 B)
│
└── ...
工作原理
启动事件循环
接收请求并创建协程处理
协程在等待 I/O 时让出控制权
事件循环管理所有运行中的协程
Django 默认使用同步处理模型
# Django 视图基本结构
def view_function(request):
# 1. 读取请求数据
user_id = request.GET.get('user_id')
# 2. 进行数据库查询(阻塞操作)
user = User.objects.get(id=user_id)
# 3. 可能进行外部 API 调用(阻塞操作)
user_stats = requests.get(f"https://api.example.com/stats/{user_id}")
# 4. 模板渲染(CPU 操作)
return render(request, 'user.html', {'user': user, 'stats': user_stats.json()})
在典型 Django 部署中:
每个进程:
加载完整的 Django 应用
包含所有中间件、URL 配置等
占用内存(通常 100MB-500MB)
每个线程:
处理单个请求
共享进程的内存空间
每个请求独占一个线程,直到请求完成
Django 常见的生产部署架构
┌── Django 进程 1 ── 线程池
│
Nginx ── 负载均衡 ── Gunicorn ── Django 进程 2 ── 线程池
│
└── Django 进程 3 ── 线程池
Django 3.1+ 开始支持异步视图和中间件
async def async_view(request):
# 可以使用 asyncio 原生功能
await asyncio.sleep(1)
# 但 ORM 仍然是同步的,需要转换
user = await sync_to_async(User.objects.get)(id=1)
# 异步模板渲染
return await sync_to_async(render)(
request, 'template.html', {'user': user}
)
关键限制:
ORM 操作本质上仍是同步的
需使用 sync_to_async 适配器转换
混合同步/异步代码可能导致性能损失
FastAPI 基于 Starlette 框架,原生支持异步
@app.get("/users/{user_id}")
async def get_user(user_id: int):
# 1. 异步数据库查询
user = await db.fetch_one("SELECT * FROM users WHERE id = :id", {"id": user_id})
# 2. 异步 HTTP 请求
async with httpx.AsyncClient() as client:
stats_response = await client.get(f"https://api.example.com/stats/{user_id}")
# 3. 所有 I/O 操作都不会阻塞事件循环
return {"user": user, "stats": stats_response.json()}
在 FastAPI 应用中:
一个事件循环:
管理所有活跃的协程
分配 CPU 时间给准备运行的协程
监控 I/O 操作的完成情况
每个请求:
由一个协程处理
遇到 await 时暂停,让出控制权
I/O 完成后恢复执行
await 是异步编程的核心机制:
暂停点:await 标记了协程可以暂停的位置
控制权转移:当执行到 await 时,控制权返回给事件循环
挂起与恢复:协程挂起等待操作完成,之后才恢复执行
async def handler():
# 这里执行同步代码
result = await async_operation()
# 在上面的 await 处,协程会暂停执行
# 事件循环可以去处理其他协程(函数)
# 当 async_operation 完成后,协程恢复执行
return result
在 FastAPI 中,await 是必须的,因为:
不使用 await 的后果
@app.get("/wrong")
async def wrong_way():
# 没有 await,返回协程对象而非结果
result = db.fetch_one("SELECT * FROM users") # 错误!
return result # 会返回一个未完成的协程对象
@app.get("/correct")
async def correct_way():
# 正确使用 await
result = await db.fetch_one("SELECT * FROM users")
return result # 返回实际查询结果
# 单个请求处理流程
─────────────────────────────────────────────────────────────────────
│ │
│ Worker 进程 │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 线程 (处理单个请求) │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │
│ │ │ │ │ │
│ │ │ 1. 接收请求 │ │ │
│ │ │ 2. 中间件处理 │ │ │
│ │ │ 3. URL 解析 │ │ │
│ │ │ 4. 视图函数 │ │ │
│ │ │ │ │ │ │
│ │ │ ├─ 数据库查询 (阻塞) │ │ │
│ │ │ │ │ │ │
│ │ │ ├─ 外部 API 调用 (阻塞) │ │ │
│ │ │ │ │ │ │
│ │ │ └─ 模板渲染 │ │ │
│ │ │ │ │ │
│ │ │ 5. 响应生成 │ │ │
│ │ │ │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
─────────────────────────────────────────────────────────────────────
特点分析
每个请求独占一个线程
I/O 操作会阻塞整个线程
大量并发请求需要大量线程
线程上下文切换开销大
内存占用高
# 多个请求同时处理流程
─────────────────────────────────────────────────────────────────────
│ │
│ 单个 Worker 进程 │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 事件循环 │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │
│ │ │ │ │ │
│ │ │ 协程 A (请求 1) │ │ │
│ │ │ ├─ 接收请求 │ │ │
│ │ │ ├─ 路径解析 │ │ │
│ │ │ ├─ 数据库查询 ──┐ │ │ │
│ │ │ │ (挂起,等待 I/O) │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ │ 协程 B (请求 2) │ │ │
│ │ │ │ │ ├─ 接收请求 │ │ │
│ │ │ │ │ ├─ 路径解析 │ │ │
│ │ │ │ │ ├─ API 调用 ───┐ │ │ │
│ │ │ │ │ │ (挂起,等待 I/O) │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ 协程 C... │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ ◄────────────┘ │ ◄────────────┘ │ │ │
│ │ │ │ (I/O 完成,恢复) │ (I/O 完成,恢复) │ │ │
│ │ │ │ │ │ │ │
│ │ │ ├─ 处理结果 ├─ 处理结果 │ │ │
│ │ │ └─ 返回响应 └─ 返回响应 │ │ │
│ │ │ │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
─────────────────────────────────────────────────────────────────────
特点分析
单个进程处理多个并发请求
I/O 操作不会阻塞事件循环
协程切换开销小
内存占用低
适合 I/O 密集型应用
# 单进程、单线程模式
python manage.py runserver
# 指定 IP 和端口
python manage.py runserver 0.0.0.0:8000
特点
单进程、单线程
不适合生产环境
自动代码重载
# 基本启动
gunicorn myproject.wsgi:application
# 多进程配置(4个工作进程)
gunicorn myproject.wsgi:application --workers=4
# 多线程配置(每个进程2个线程)
gunicorn myproject.wsgi:application --workers=4 --threads=2
# 自动工作进程数(CPU核心数 x 2 + 1)
gunicorn myproject.wsgi:application --workers=$(( 2 * $(nproc) + 1 ))
进程数量计算
常见公式:(2 × CPU核心数) + 1
基于内存限制的计算:可用内存 ÷ 每个进程内存占用
# uwsgi.ini 配置文件
[uwsgi]
module = myproject.wsgi:application
master = true
processes = 4
threads = 2
socket = /tmp/myproject.sock
# 启动命令
uwsgi --ini uwsgi.ini
# 基本启动(单进程)
uvicorn main:app --reload
# 指定 IP 和端口
uvicorn main:app --host 0.0.0.0 --port 8000
特点
单进程、单事件循环
支持代码热重载
适合开发环境
# 不使用热重载
uvicorn main:app --host 0.0.0.0 --port 8000
# 多进程模式需要 Gunicorn
gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app
多进程异步配置
每个进程运行一个 Uvicorn 实例
每个 Uvicorn 实例有一个事件循环
进程间不共享内存,相互独立
# 使用 Uvicorn 的工作进程
uvicorn main:app --workers 4
每个进程:~200-500MB 基础内存
每个线程:~2-10MB 额外内存
总内存:进程数 × (基础内存 + 线程数 × 每线程内存)
例如,4个进程,每个2个线程:4 × (400MB + 2 × 5MB) = 1,640MB
每个进程:~150-300MB 基础内存
每个协程:~几KB 额外内存
总内存:进程数 × 基础内存 + 活跃协程数 × 每协程内存
例如,2个进程,1000个并发请求:2 × 250MB + 1000 × 2KB = 502MB
I/O 操作时,线程闲置但仍占用资源
大量闲置线程导致上下文切换开销
CPU 利用率通常不均衡:大量等待,少量计算
I/O 操作时释放 CPU 资源给其他协程
协程切换开销小
CPU 利用率更均衡:更少的闲置时间