pypy 在 web 框架中常“不快反慢”,因其 jit 对 i/o 密集型及依赖 c 扩展的场景无效,反而引入兼容性开销;仅当 cpu 密集、纯 python 依赖、同步服务器且瓶颈确在 python 层时才可能增益。

PyPy 不能直接加速大多数 Web 框架的请求处理速度,尤其在 I/O 密集型场景下,实际性能可能反而下降。
为什么 PyPy 在 Web 框架中常“不快反慢”
Web 框架(如 Flask、Django、FastAPI)的核心瓶颈通常不在 Python 字节码执行,而在网络 I/O、数据库查询、模板渲染或 JSON 序列化等环节。PyPy 的 JIT 对纯计算密集型代码有明显优势,但对大量调用 C 扩展(psycopg2、numpy、ujson、gevent)或阻塞式 socket 操作的场景,不仅无法加速,还可能因兼容性问题触发回退路径或额外开销。
常见现象包括:
-
ImportError: cannot import name '...' from 'cryptography.hazmat.bindings._openssl'—— 许多安全/加密库未完全适配 PyPy - 使用
gevent时出现协程调度异常或内存泄漏 -
uvicorn+asyncio在 PyPy 下 event loop 吞吐量低于 CPython
哪些 Web 场景值得尝试 PyPy
仅当满足以下全部条件时,PyPy 才可能带来可观收益:
- 框架逻辑高度 CPU 密集(例如:自定义中间件做大量字符串解析、规则引擎、实时数据脱敏)
- 依赖库全部通过
pip install在 PyPy 环境下成功构建(优先选纯 Python 实现,如pure-python-adb类库) - 使用同步服务器(如
waitress或gunicorn --worker-class sync),避开 asyncio/uvloop 兼容陷阱 - 已确认瓶颈确实在 Python 层(用
pypy-cprofile或py-spy record验证)
示例可行组合:Flask + waitress + markdown-it-py(纯 Python Markdown 解析器)+ 内存中缓存计算结果。
正确启动 PyPy Web 应用的关键步骤
不要直接替换 python 为 pypy 就运行 flask run —— 开发服务器会加载过多调试模块,掩盖真实性能特征,且热重载在 PyPy 下不稳定。
- 用
pypy -m venv venv-pypy创建独立环境,再source venv-pypy/bin/activate - 安装时加
--no-binary :all:强制从源码编译(尤其对cffi-based 库如cryptography) - 生产启动必须用 WSGI/ASGI 服务器:如
gunicorn --pythonpath . -w myapp:app -k gevent --worker-class sync(注意gevent需用pip install gevent --no-binary gevent) - 禁用
__pycache__和字节码写入:启动时加-B参数(pypy -B -m gunicorn ...),避免 PyPy 自己的.pypy缓存干扰
比换解释器更有效的提速手段
绝大多数 Web 应用的性能卡点根本不在 Python 解释器层。与其花时间适配 PyPy,不如优先检查:
- 数据库查询是否 N+1?有没有加
select_related或defer()(Django)? - 静态文件是否走 CDN?模板是否启用
django.template.loaders.cached.Loader? - JSON 响应是否用了
orjson或ujson替代内置json? - 是否遗漏了连接池配置(如
SQLALCHEMY_ENGINE_OPTIONS = {"pool_pre_ping": True})?
PyPy 的兼容性成本高、见效范围窄,真正需要它的时候,往往已经做了足够多 profiling,也清楚自己在优化哪一段纯 Python 循环 —— 那时再切不迟。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











