跳到主要内容

Cython 与编译加速

问题

如何加速 Python 的 CPU 密集型代码?Cython、Numba、PyPy 各有什么特点?

答案

Cython

将 Python 代码编译为 C 扩展,通过静态类型声明大幅提速:

fast_math.pyx
# cython: boundscheck=False, wraparound=False

def fibonacci(int n):
cdef int a = 0, b = 1, i
for i in range(n):
a, b = b, a + b
return a
# 编译
cythonize -i fast_math.pyx

Numba(JIT 编译)

通过装饰器即时编译,无需修改代码结构:

from numba import njit
import numpy as np

@njit # Just-In-Time 编译
def monte_carlo_pi(n: int) -> float:
count = 0
for i in range(n):
x = np.random.random()
y = np.random.random()
if x * x + y * y <= 1.0:
count += 1
return 4.0 * count / n

# 首次调用触发编译,之后调用极快
result = monte_carlo_pi(10_000_000)

对比

方案加速倍数学习成本适用场景
Cython10-100x高(需学 Cython 语法)库开发、核心算法
Numba10-100x低(加装饰器即可)数值计算、NumPy 操作
PyPy2-10x零(替换解释器)整个程序加速
C 扩展100x+极高极致性能需求

PyPy

# 直接用 PyPy 运行现有代码
pypy3 myapp.py
PyPy 限制

PyPy 不支持 C 扩展(如 NumPy 的 C 部分),适合纯 Python 代码。科学计算项目不推荐。


常见面试问题

Q1: Numba 的原理?

答案

Numba 使用 LLVM 编译器将带 @njit 装饰的 Python 函数编译为机器码。首次调用时触发编译(有延迟),之后直接执行机器码。支持 NumPy 数组操作,但不支持任意 Python 对象。

Q2: 什么时候该用 C 扩展?

答案

当 Cython/Numba 无法满足且对性能要求极致时(如密码学、图像处理核心算法)。现代推荐使用 pybind11PyO3(Rust)代替手写 CPython C API。

相关链接