pypy 仅对长时间运行、计算密集、循环多、对象生命周期稳定的纯 python 代码提速 2–5 倍,如数值循环、解析器、游戏逻辑等;依赖 c 扩展(如 numpy)或 cpython 特有 api 时反而更慢或报错。

PyPy 通常不能直接“替代 CPython 实现数倍提速”——它只对特定类型代码有效,盲目切换反而可能更慢甚至报错。
哪些 Python 代码在 PyPy 下真能快 2–5 倍?
PyPy 的 JIT 编译器对“长时间运行、计算密集、循环多、对象生命周期稳定”的代码最友好。典型场景包括:
- 数值计算(非 NumPy,而是纯 Python 的
for循环累加、矩阵乘法模拟) - 解析器/编译器前端(如手写递归下降解析器)
- 游戏逻辑循环(不依赖 C 扩展的纯 Python 游戏主循环)
- 某些爬虫的 HTML 文本处理(正则 + 字符串拼接密集型)
反之,如果程序启动即退出(如 CLI 工具)、大量调用 C 扩展(numpy、cv2、psycopg2)、或重度依赖 CPython 特有 API(sys._getframe()、gc.get_objects()),PyPy 不仅不快,还可能直接失败。
安装与运行时必须检查的三件事
别只执行 pypy3 script.py 就以为万事大吉。实际落地前务必验证:
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
-
import sys; print(sys.implementation.name)—— 确认运行时确实是pypy,不是误用了系统默认的python3 - 所有依赖是否支持 PyPy:
pypy3 -m pip list后手动查包文档,重点盯numpy(需装pip install numpy,但版本受限)、cffi(推荐)、ctypes(可用,cython编译的模块则大概率不兼容) - 避免使用 CPython 私有属性:例如
func.__code__.co_lnotab在 PyPy 中结构不同;threading._active是内部实现,PyPy 不提供
为什么你的 NumPy 代码在 PyPy 里反而变慢了?
PyPy 自身不加速 numpy 调用——因为 numpy 核心是 C 实现,PyPy 只能做 FFI 调用,绕不开 CPython 的 ABI 兼容层。此时你获得的是:
- 更低的 Python 层开销(比如循环控制、索引查找)
- 但更高的 C 调用开销(PyPy 的 cpyext 层比 CPython 的原生调用慢 10–30%)
- 最终结果常是“整体持平甚至略降”,尤其当数组操作占主导时
真正受益的组合是:PyPy + 纯 Python 数值逻辑 + cffi 封装关键 C 函数。例如用 cffi 把热点循环写成 C,再由 PyPy JIT 高效调度,这才是提速正解。
调试 PyPy 报错时最容易忽略的细节
PyPy 的错误栈和对象模型与 CPython 不同,常见陷阱:
-
__del__方法触发时机不可靠(PyPy 的 GC 不保证顺序),别在里面做资源清理 -
sys.settrace()和sys.setprofile()在 PyPy 中性能极差,禁用或换用pypy-cpptracing类工具 - 路径相关行为差异:PyPy 的
site-packages默认不在sys.path[0],虚拟环境激活后仍要确认pip安装目标是否正确 - 调试器支持弱:
pdb可用,但ipdb/ptpdb可能崩溃,建议用pypy3 -m pdb script.py原生命令
真实项目中,PyPy 不是“一键替换就能提速”的银弹,而是需要你重新评估热点分布、隔离 C 扩展依赖、并接受部分语言特性的让步。最常被低估的,其实是迁移后的测试成本——同一段代码,在 CPython 下通过的单元测试,在 PyPy 下可能因浮点误差累积、字典插入顺序、或线程调度差异而失败。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










