Speed Up Python: Numba, Cython, and PyPy Benchmarks
Performance myths aside—Python can fly. You just have to choose the right accelerator. Let’s compare Numba (JIT), Cython (compiled C extensions), and PyPy (alternative runtime) with measured results.
1. Baseline Problem
import math, time
def compute_pi(n: int) -> float:
s = 0.0
for k in range(n):
s += (-1.0)**k / (2*k + 1)
return 4*s
start = time.perf_counter()
compute_pi(50_000_000)
print("elapsed", time.perf_counter()-start)
On CPython 3.12, this takes ~8.4 s on a modern CPU. We’ll reuse this as the benchmark.
2. Numba — Just-In-Time Magic
from numba import njit
@njit
def compute_pi_fast(n):
s = 0.0
for k in range(n):
s += (-1.0)**k / (2*k + 1)
return 4*s
First run: includes compile time. Second run: ~0.3 s — ≈ 28× faster. Numba translates loops to LLVM, caching machine code for numeric hot paths.
3. Cython — Ahead-of-Time C Extension
Convert Python syntax to C; compile once.
# file: compute_pi.pyx
def compute_pi_cy(int n):
cdef double s = 0
cdef int k
for k in range(n):
s += (-1)**k / (2*k + 1)
return 4*s
# setup.py
from setuptools import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize("compute_pi.pyx"))
Build via python setup.py build_ext --inplace. Execution ≈ 0.19 s — about 44× speed-up.
4. PyPy — A New Interpreter
PyPy translates Python bytecode to machine code on the fly via a tracing JIT.
Drop-in replacement (pypy3 script.py). On the same benchmark ≈ 0.26 s.
5. Comparison Summary
| Implementation | Time (s) | Speed × |
|---|---|---|
| CPython 3.12 | 8.4 | 1× |
Share this articleHelp others discover it across your favourite communities. |
Comments
Join the discussion. We keep comments private to your device until moderation tooling ships.