PyO3 + Maturin Skill
Python modules backed by Rust, only after a measured CPU hotspot.
When to Use
- Creating or modifying a Python module backed by Rust
- Speeding up a confirmed CPU-bound hotspot
- Packaging Rust as a Python extension
- Debugging Maturin/PyO3 develop, build, or import issues
When Not to Use
- I/O-bound bottlenecks
- No profiling evidence
- NumPy / Polars / SciPy already solve it
- Pure Python feature work
Related Skills
- Use python-performance first to confirm a CPU-bound hotspot.
- Use python-testing for parity and regression tests.
- Use doubt-driven-development when this is the first native module in a pure-Python repo. Rust API/unsafe: rust-pro.
Decision Gate
All must be true:
- Hotspot profiled and CPU-bound
- Pure compute or needs low-level control (memory, SIMD, threads)
- Expected speedup justifies build/maintenance cost
- Python API boundary stays small and stable
Prefer extracting a hot function over rewriting a module.
Recommended Stack
- PyO3, Maturin (
maturin develop,maturin build) pyproject.toml+Cargo.tomluvfor the Python env
Mixed Layout
my-project/
pyproject.toml # [build-system] requires = ["maturin>=1.0"]
Cargo.toml # crate-type = ["cdylib"]
python/my_project/__init__.py
src/lib.rs # #[pymodule]
[tool.maturin] python-source = "python"- Native submodule e.g.
my_project._native - Ignore
*.so,*.pyd,target/
GIL
- Extract/copy args while holding the GIL
py.allow_threads(...)for compute- Pure Rust (Rayon only after detaching)
- Return
PyResult<T>mapped to Python exceptions
Never hold the GIL in long CPU loops. Minimize boundary crossings; process bulk data.
Maturin Workflow
- Profile (
python-performance) - Minimal interface
maturin developin the active venvpytestparity- Benchmark with
maturin develop --release - Commit only after measurable gains
Troubleshooting
- ImportError: symbol not found:
#[pymodule]name matches the.so/.pyd - Slow: not a
--releasebuild - Rayon deadlock:
allow_threadsbefore parallel iterators - Wheels:
--zigorabi3as needed
Final Checklist
- CPU-bound hotspot profiled
- Small stable Python ↔ Rust boundary
- Mixed layout
- GIL released during compute
-
PyResult<T>with meaningful exceptions -
maturin develop --release+ pytest pass - Build artifacts gitignored