--workers仅在CPU利用率长期低于60%、存在同步阻塞或GPU显存未充分利用时才有效;盲目增加会导致OOM、连接池耗尽或吞吐下降,须结合物理核心数、内存容量和请求模式谨慎设定。

--workers 参数不是“开越多越快”,它只在特定瓶颈下生效:单进程被同步阻塞卡死、CPU 利用率长期低于 60% 但 QPS 上不去、或 GPU 显存未被 batch 充分利用时,才值得启用。盲目设 --workers 8 可能导致内存 OOM、连接池爆满、缓存不一致,甚至吞吐下降。
什么时候必须加 --workers?看三个硬指标
Uvicorn 单进程靠 async/await 已能轻松扛住数千 I/O 请求。加 --workers 不是默认动作,而是对症下药:
- 压测时
htop显示 CPU 利用率持续低于 60%,但请求延迟飙升、QPS 卡在瓶颈 —— 说明单核吃不满,需要多进程并行 - 代码里存在无法避免的同步阻塞调用:比如
time.sleep(1)、requests.get()、pandas.read_csv()或未封装进run_in_executor的 numpy 计算 - 部署的是推理服务(如 LLM 前处理或图像 batch 推理),单 worker 只能串行发请求,GPU 显存和算力大量闲置
--workers 数值怎么定?别信“2×CPU+1”
真实取值取决于三件事,且互相制约:
Uvicorn 0.52.1 是 Python ASGI Web 服务器,提供异步应用服务及 WebSocket 支持,常用于 FastAPI、Starlette 等应用的开发和部署。本下载为官方 PyPI 通用 wheel 包,可使用 pip 安装,并由包管理器处理所需依赖。
- 查物理核心数:
nproc输出为 4,--workers 4是安全起点;超过 8 后吞吐增长通常趋缓 - 看内存容量:每个 worker 是独立 Python 进程,加载一次大模型就占一份显存/CPU 内存;RTX 3060(12GB)实测最多稳住 4 个 worker,再多必
MemoryError - 观察请求模式:如果流量极不均匀(例如每分钟集中来 100 个大 batch),worker 数宁少勿多,避免空转开销和冷启动延迟
常见失效场景:设了 --workers 却没看到多个进程
启动后 ps aux | grep uvicorn 只看到 1 个主进程?大概率掉进这些坑:
- 同时启用了
--reload:二者互斥,--reload强制降级为单进程,且 fork 失败时静默回退 - 用 Gunicorn 做前置但漏写
-k uvicorn.workers.UvicornWorker:Gunicorn 默认起的是同步 worker,async 路由直接报TypeError: 'coroutine' object is not callable - Docker 容器未配 CPU quota:
docker run --cpus=2却设--workers 4,内核调度失灵,部分 worker 启动即被 kill - Windows 环境下用
spawn启动方式(默认),模块顶层代码被重复执行,可能触发重复初始化错误
多 worker 下的共享资源必须重设计
每个 worker 进程完全隔离,模块级全局变量、数据库连接池、Redis 客户端都不是共享的:
-
lifespan的startup和shutdown会在每个 worker 里各执行一次 —— 不要在这里初始化全局 cache 或发通知 - 顶层写的
db_pool = create_pool(...)会被复制 N 份,容易触发psycopg2.OperationalError: too many clients - 日志 handler 若未做进程安全配置,会导致日志重复写入、文件锁冲突
- 正确做法:所有共享状态走外部存储(Redis 缓存、PostgreSQL 序列号)、连接池用 lazy init + 单例控制、生命周期逻辑收口到依赖注入容器
真正难的从来不是加几个数字,而是判断当前瓶颈是否属于多进程能解决的类型,以及能否承受进程隔离带来的状态管理复杂度。多数性能问题其实出在异步调用没写对、连接池没复用、或 SQL 没加索引——先确认这些,再碰 --workers。

















