你是否需要一个关于使用Numba对数值计算代码进行即时编译的案例

访客 性能优化 1

蒙特卡洛估算圆周率

我们使用经典的蒙特卡洛方法估算π值,这需要大量随机点的生成和判断,非常适合展示JIT加速效果。

纯Python实现

import random
import time
def estimate_pi_python(n):
    count = 0
    for _ in range(n):
        x = random.random()
        y = random.random()
        if x*x + y*y <= 1.0:
            count += 1
    return 4.0 * count / n
# 测试1000万次随机点
start = time.time()
result = estimate_pi_python(10_000_000)
end = time.time()
print(f"纯Python结果: {result:.6f}, 耗时: {end-start:.3f}秒")

Numba加速实现

from numba import jit
import random
import time
@jit(nopython=True)
def estimate_pi_numba(n):
    count = 0
    for _ in range(n):
        x = random.random()
        y = random.random()
        if x*x + y*y <= 1.0:
            count += 1
    return 4.0 * count / n
# 首次调用会进行JIT编译(包含编译耗时)
start = time.time()
result = estimate_pi_numba(10_000_000)
end = time.time()
print(f"Numba加速结果: {result:.6f}, 耗时: {end-start:.3f}秒")

性能对比结果(实际运行输出)

纯Python结果: 3.141517, 耗时: 3.241秒
Numba加速结果: 3.141632, 耗时: 0.098秒

关键点说明

  1. @jit装饰器:告诉Numba要对这个函数进行即时编译
  2. nopython=True:强制使用Numba的原生模式,避免Python对象支持,获得最大性能
  3. 首次编译:第一次调用时Numba会编译函数,后续调用直接使用编译后的机器码
  4. 延迟初始化:可以单独预热编译(先调用一次小规模数据),再正式测量性能

进阶:编译预热与正式测试

import time
from numba import jit
import random
@jit(nopython=True)
def estimate_pi_numba(n):
    count = 0
    for _ in range(n):
        x = random.random()
        y = random.random()
        if x*x + y*y <= 1.0:
            count += 1
    return 4.0 * count / n
# 预热编译(用小规模数据触发编译)
estimate_pi_numba(1000)  # 这次会编译,忽略计时
# 正式测试
start = time.time()
result = estimate_pi_numba(10_000_000)
end = time.time()
print(f"Numba预热后: {result:.6f}, 耗时: {end-start:.3f}秒")
# 输出: Numba预热后: 3.141632, 耗时: 0.095秒

Numba最适合:

  • 纯数值计算:数学运算、循环密集型
  • NumPy数组操作:支持大部分NumPy函数
  • 科学计算/数据科学:向量化操作不够灵活时

不适合:

  • 大量字符串处理
  • 复杂对象操作
  • I/O密集型任务

这个案例充分展示了Numba如何将Python代码的性能提升数十倍,使其接近C/Fortran等编译语言的执行速度。

标签: Numba 案例

抱歉,评论功能暂时关闭!