Skip to main content

uvicorn

1. Uvicorn 是什么?它解决什么问题?

Uvicorn 是一个轻量级、超快速的 ASGI(异步服务器网关接口)服务器 。它是运行 FastAPI、Starlette 等异步 Web 应用的服务器程序。

1.1 为什么需要 Uvicorn?

简单理解

  • FastAPI/Starlette :Web 框架,定义了如何处理请求和返回响应
  • Uvicorn :服务器,负责接收 HTTP 请求、调用框架、返回响应

类比

  • 框架 = 餐厅的菜单和厨师(定义做什么菜)
  • 服务器 = 餐厅的服务员(负责接待客人、传递订单)

1.2 Uvicorn 的核心特点

  1. 极高性能 :基于 uvloop(高性能事件循环)和 httptools(C 语言 HTTP 解析器)
  2. ASGI 兼容 :完全支持异步 Web 应用
  3. 轻量级 :代码简洁,依赖少
  4. 易于使用 :简单的命令行接口和 Python API

2. 前置知识

在学习 Uvicorn 之前,你需要了解以下基础知识。

2.1 什么是服务器?

服务器(Server) 是运行在计算机上的程序,它:

  • 监听网络端口(如 8000)
  • 接收客户端(如浏览器)的请求
  • 处理请求并返回响应

简单理解 :服务器就像一个餐厅,等待客人(客户端)来点餐(发送请求),然后提供食物(返回响应)。

2.2 什么是 ASGI?

ASGI(Asynchronous Server Gateway Interface,异步服务器网关接口) 是 Python Web 应用和服务器之间的标准接口。

ASGI vs WSGI

  • WSGI (旧标准):同步接口,一次只能处理一个请求
  • ASGI (新标准):异步接口,可以同时处理多个请求

为什么需要 ASGI

  • 支持异步编程(async/await
  • 支持 WebSocket
  • 性能更好

2.3 异步编程基础

Uvicorn 是异步服务器,你需要了解:

  • async def :定义异步函数
  • await :等待异步操作完成
  • asyncio :Python 的异步编程库

如果你不熟悉异步编程,建议先学习 Python 的 asyncio 模块。

2.4 Python 基础知识

你需要熟悉:

  • 模块导入import 语句
  • 函数调用 :如何调用函数
  • 命令行 :基本的命令行操作

3. 安装与环境准备

3.1 安装 Uvicorn

使用 pip 安装:

# 标准版(推荐)
pip install uvicorn[standard]

# 或者基础版
pip install uvicorn

说明

  • uvicorn[standard]:包含所有推荐依赖(uvloop、httptools 等),性能更好
  • uvicorn:基础版本,功能完整但性能稍差

3.2 验证安装

创建一个简单的测试应用 test_app.py

# 导入必要的模块
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route

# 定义处理函数
async def homepage(request):
# 返回 JSON 响应
return JSONResponse({"message": "Uvicorn 安装成功!"})

# 创建应用
app = Starlette(
routes=[
Route("/", homepage),
]
)

# 运行应用(使用 uvicorn)
if __name__ == "__main__":
import uvicorn
# 运行服务器,监听 8000 端口
uvicorn.run(app, host="0.0.0.0", port=8000)

运行测试:

python test_app.py

然后在浏览器访问 http://localhost:8000,应该能看到 {"message": "Uvicorn 安装成功!"}

4. 基本使用:命令行方式

Uvicorn 最简单的使用方式是通过命令行运行。

4.1 创建示例应用

首先,创建一个简单的应用 main.py

# 导入必要的模块
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route

# 定义处理函数
async def read_root(request):
# 返回 JSON 响应
return JSONResponse({"message": "Hello Uvicorn!"})

# 创建应用实例
# 变量名必须是 app(命令行默认查找这个变量)
app = Starlette(
routes=[
Route("/", read_root),
]
)

4.2 运行应用

在命令行中运行:

# 基本运行(默认监听 127.0.0.1:8000)
uvicorn main:app

# 指定主机和端口
uvicorn main:app --host 0.0.0.0 --port 8000

# 启用热重载(开发模式,代码修改后自动重启)
uvicorn main:app --reload

# 设置日志级别
uvicorn main:app --log-level debug

命令说明

  • main:appmain 是文件名(不含 .py),app 是应用实例的变量名
  • --host 0.0.0.0:监听所有网络接口(允许外部访问)
  • --port 8000:使用 8000 端口
  • --reload:开发模式,代码修改后自动重启服务器
  • --log-level debug:设置日志级别为 debug(显示详细信息)

5. 基本使用:Python 代码方式

除了命令行,你也可以在 Python 代码中直接运行 Uvicorn。

5.1 使用 uvicorn.run() 函数

# 导入必要的模块
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
import uvicorn

# 定义处理函数
async def read_root(request):
# 返回 JSON 响应
return JSONResponse({"message": "Hello from Python!"})

# 创建应用实例
app = Starlette(
routes=[
Route("/", read_root),
]
)

# 在 Python 代码中运行服务器
# uvicorn.run() 函数用于启动服务器
if __name__ == "__main__":
# 方式 1:传入应用实例
uvicorn.run(
app, # 应用实例
host="0.0.0.0", # 主机地址
port=8000, # 端口号
reload=True # 是否启用热重载(开发模式)
)

5.2 使用字符串指定应用

# 导入必要的模块
import uvicorn

# 使用字符串指定应用位置
# "main:app" 表示 main.py 文件中的 app 变量
if __name__ == "__main__":
uvicorn.run(
"main:app", # 应用位置(字符串格式)
host="0.0.0.0", # 主机地址
port=8000, # 端口号
reload=True, # 启用热重载
log_level="info" # 日志级别
)

两种方式的区别

  • 传入应用实例 :直接传入应用对象,更直观
  • 传入字符串 :Uvicorn 会自动导入,适合应用在其他文件中定义

6. 常用配置选项

Uvicorn 提供了丰富的配置选项,让我们学习最常用的几个。

6.1 基本配置

# 导入必要的模块
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
import uvicorn

# 定义处理函数
async def read_root(request):
return JSONResponse({"message": "Hello Uvicorn!"})

# 创建应用
app = Starlette(
routes=[
Route("/", read_root),
]
)

# 运行应用,配置常用选项
if __name__ == "__main__":
uvicorn.run(
app,
host="0.0.0.0", # 主机地址(0.0.0.0 表示监听所有网络接口)
port=8000, # 端口号
reload=True, # 是否启用热重载(开发时使用)
log_level="info", # 日志级别:critical, error, warning, info, debug, trace
access_log=True, # 是否记录访问日志
workers=1 # 工作进程数(开发时通常为 1,生产环境可以增加)
)

6.2 开发环境配置

# 导入必要的模块
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
import uvicorn

# 定义处理函数
async def read_root(request):
return JSONResponse({"message": "开发模式"})

# 创建应用
app = Starlette(
routes=[
Route("/", read_root),
]
)

# 开发环境配置
if __name__ == "__main__":
uvicorn.run(
app,
host="127.0.0.1", # 只监听本地(更安全)
port=8000,
reload=True, # 启用热重载
reload_dirs=["./"], # 监听哪些目录的变化
log_level="debug", # 详细的日志(便于调试)
access_log=True # 记录访问日志
)

6.3 生产环境配置(简化版)

# 导入必要的模块
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
import uvicorn

# 定义处理函数
async def read_root(request):
return JSONResponse({"message": "生产模式"})

# 创建应用
app = Starlette(
routes=[
Route("/", read_root),
]
)

# 生产环境配置(简化版)
if __name__ == "__main__":
uvicorn.run(
app,
host="0.0.0.0", # 监听所有网络接口
port=8000,
reload=False, # 禁用热重载(生产环境不需要)
log_level="warning", # 只记录警告和错误
access_log=True, # 记录访问日志
workers=4 # 使用多个工作进程(根据 CPU 核心数调整)
)

配置说明

  • host :服务器监听的主机地址
    • 127.0.0.1:只允许本地访问
    • 0.0.0.0:允许所有网络接口访问
  • port :服务器监听的端口号
  • reload :是否启用热重载(开发时使用,生产环境禁用)
  • log_level :日志级别,从低到高:critical < error < warning < info < debug < trace
  • access_log :是否记录访问日志
  • workers :工作进程数(多进程模式,提高并发能力)

7. 运行 FastAPI 应用

Uvicorn 最常用的场景是运行 FastAPI 应用。

7.1 创建 FastAPI 应用

# 导入 FastAPI
from fastapi import FastAPI

# 创建 FastAPI 应用实例
app = FastAPI()

# 定义路由
@app.get("/")
async def read_root():
# 返回 JSON 响应
return {"message": "Hello FastAPI with Uvicorn!"}

# 运行应用
if __name__ == "__main__":
import uvicorn
# 运行 FastAPI 应用
uvicorn.run(app, host="0.0.0.0", port=8000, reload=True)

7.2 使用命令行运行

# 运行 FastAPI 应用
uvicorn main:app --reload

# 访问 http://localhost:8000 查看应用
# 访问 http://localhost:8000/docs 查看自动生成的 API 文档

8. 运行 Starlette 应用

Uvicorn 也可以运行 Starlette 应用。

8.1 创建 Starlette 应用

# 导入必要的模块
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route

# 定义处理函数
async def read_root(request):
# 返回 JSON 响应
return JSONResponse({"message": "Hello Starlette with Uvicorn!"})

# 创建 Starlette 应用实例
app = Starlette(
routes=[
Route("/", read_root),
]
)

# 运行应用
if __name__ == "__main__":
import uvicorn
# 运行 Starlette 应用
uvicorn.run(app, host="0.0.0.0", port=8000, reload=True)

8.2 使用命令行运行

# 运行 Starlette 应用
uvicorn main:app --reload

# 访问 http://localhost:8000 查看应用

9. 热重载:开发时的便利功能

热重载(Hot Reload) 是开发时的便利功能:当你修改代码后,服务器会自动重启,无需手动停止和启动。

9.1 启用热重载

# 导入必要的模块
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
import uvicorn

# 定义处理函数
async def read_root(request):
# 修改这里的返回值,保存文件后服务器会自动重启
return JSONResponse({"message": "修改我,然后保存文件!"})

# 创建应用
app = Starlette(
routes=[
Route("/", read_root),
]
)

# 启用热重载
if __name__ == "__main__":
uvicorn.run(
app,
host="0.0.0.0",
port=8000,
reload=True, # 启用热重载
reload_dirs=["./"] # 监听当前目录的变化
)

使用方法

  1. 运行程序
  2. 修改代码(如修改返回的消息)
  3. 保存文件
  4. 服务器会自动检测变化并重启
  5. 刷新浏览器即可看到新内容

注意 :热重载只在开发时使用,生产环境应该禁用(reload=False)。

10. 日志配置:查看服务器运行信息

Uvicorn 提供了详细的日志功能,帮助你了解服务器的运行状态。

10.1 日志级别

# 导入必要的模块
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
import uvicorn

# 定义处理函数
async def read_root(request):
return JSONResponse({"message": "查看日志输出"})

# 创建应用
app = Starlette(
routes=[
Route("/", read_root),
]
)

# 配置不同的日志级别
if __name__ == "__main__":
uvicorn.run(
app,
host="0.0.0.0",
port=8000,
log_level="debug", # 日志级别:critical, error, warning, info, debug, trace
access_log=True # 是否记录访问日志
)

日志级别说明

  • critical :只显示严重错误
  • error :显示错误信息
  • warning :显示警告信息
  • info :显示一般信息(默认)
  • debug :显示调试信息(最详细)
  • trace :显示跟踪信息(最最详细)

10.2 查看日志输出

运行服务器后,你会看到类似以下的日志输出:

INFO:     Started server process [12345]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO: 127.0.0.1:54321 - "GET / HTTP/1.1" 200 OK

日志说明

  • 第一行:服务器进程已启动
  • 第二行:等待应用启动
  • 第三行:应用启动完成
  • 第四行:服务器运行地址
  • 第五行:访问日志(客户端 IP、请求方法、路径、状态码)

11. 多进程模式:提高并发能力

默认情况下,Uvicorn 使用单进程模式。对于生产环境,可以使用多进程模式提高并发能力。

11.1 单进程模式(开发环境)

# 导入必要的模块
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
import uvicorn

# 定义处理函数
async def read_root(request):
return JSONResponse({"message": "单进程模式"})

# 创建应用
app = Starlette(
routes=[
Route("/", read_root),
]
)

# 单进程模式(默认)
if __name__ == "__main__":
uvicorn.run(
app,
host="0.0.0.0",
port=8000,
workers=1 # 单进程(开发环境)
)

11.2 多进程模式(生产环境)

# 导入必要的模块
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
import uvicorn
import multiprocessing

# 定义处理函数
async def read_root(request):
return JSONResponse({"message": "多进程模式"})

# 创建应用
app = Starlette(
routes=[
Route("/", read_root),
]
)

# 多进程模式
if __name__ == "__main__":
# 获取 CPU 核心数
cpu_count = multiprocessing.cpu_count()
# 工作进程数通常是 CPU 核心数的 2 倍 + 1
workers = cpu_count * 2 + 1

uvicorn.run(
app,
host="0.0.0.0",
port=8000,
workers=workers, # 多进程(生产环境)
reload=False # 生产环境禁用热重载
)

说明

  • 单进程模式 :适合开发环境,简单易用
  • 多进程模式 :适合生产环境,提高并发处理能力
  • workers 数量 :通常设置为 CPU 核心数的 2 倍 + 1

12. 常见错误与最佳实践

12.1 常见错误

错误 1:找不到应用

# 错误:应用变量名不匹配
# main.py 中定义的是 my_app,但命令行使用的是 app
uvicorn main:app # 错误:找不到 app 变量

# 正确:使用正确的变量名
uvicorn main:my_app # 正确

错误 2:端口已被占用

# 错误:端口 8000 已被其他程序占用
uvicorn.run(app, port=8000) # 可能报错:Address already in use

# 正确:使用其他端口
uvicorn.run(app, port=8001) # 使用 8001 端口

错误 3:忘记启用热重载

# 开发时忘记启用热重载,每次修改代码都要手动重启
uvicorn.run(app, reload=False) # 不方便

# 正确:开发时启用热重载
uvicorn.run(app, reload=True) # 方便

12.2 最佳实践

  1. 开发环境

    • 使用 reload=True 启用热重载
    • 使用 log_level="debug" 查看详细信息
    • 使用 workers=1 单进程模式
  2. 生产环境

    • 使用 reload=False 禁用热重载
    • 使用 log_level="warning" 只记录警告和错误
    • 使用 workers=4 或更多(根据 CPU 核心数)
  3. 端口选择

    • 开发环境:使用 8000、8001 等常用端口
    • 生产环境:使用标准端口(80、443)或配置反向代理

13. Uvicorn 与其他组件的关系

13.1 Uvicorn 在 Web 开发中的位置

客户端(浏览器)

Uvicorn(服务器)

FastAPI/Starlette(框架)

你的应用代码

简单理解

  • 客户端 :发送请求(如浏览器)
  • Uvicorn :接收请求,调用框架
  • 框架 :处理请求,执行你的代码
  • 你的代码 :处理业务逻辑,返回响应

13.2 为什么选择 Uvicorn?

  1. 性能优秀 :基于 uvloop 和 httptools,性能极佳
  2. 简单易用 :配置简单,API 清晰
  3. 生态良好 :与 FastAPI、Starlette 完美集成
  4. 功能完整 :支持异步、WebSocket 等特性

14. 总结

14.1 核心概念回顾

  • Uvicorn :ASGI 服务器,用于运行异步 Web 应用
  • ASGI :异步服务器网关接口
  • 热重载 :开发时自动重启服务器
  • 多进程模式 :提高并发处理能力
  • 日志级别 :控制日志输出的详细程度

14.2 基本使用流程

  1. 安装 Uvicorn:pip install uvicorn[standard]
  2. 创建应用(FastAPI 或 Starlette)
  3. 运行应用:
    • 命令行:uvicorn main:app --reload
    • Python 代码:uvicorn.run(app, host="0.0.0.0", port=8000)