当你的 Python 代码遇到性能瓶颈时,该怎么办?重写为 C++?迁移到 Go?在 2026 年,有一个更优雅的答案:PyO3 + Rust。
Python 以简洁易用著称,但受限于 GIL 和解释器开销,计算密集型任务往往力不从心。Rust 则提供了与 C++ 媲美的性能,同时保证内存安全。PyO3 作为两者的桥梁,让你能在保持 Python 接口简洁的同时,获得 Rust 的速度优势。
本教程将带你从零开始,使用现代化构建工具 Maturin,构建一个生产级的 RustPython 混合项目。你将学会:
- PyO3 的核心概念与工作原理
- 使用 Maturin 快速搭建项目骨架
- 编写高性能 Rust 扩展函数并暴露给 Python
- 处理复杂数据类型与 GIL 管理
- 调试、测试与发布生产级扩展模块
准备工作:环境与工具链
开始之前,确保你的开发环境满足以下要求:
安装 Rust(如尚未安装):
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup update stable
创建并激活 Python 虚拟环境:
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
在虚拟环境中安装 Maturin:
pip install maturin
实战步骤
初始化 PyO3 项目
使用 Maturin 的脚手架命令快速创建项目骨架:
maturin new hypercalc --bindings pyo3
cd hypercalc
项目结构如下:
hypercalc/
├── Cargo.toml # Rust 包配置
├── pyproject.toml # Python 包配置
├── src/
│ └── lib.rs # Rust 源码入口
└── python/ # 可选的纯 Python 模块
配置 Cargo.toml
打开 Cargo.toml,确认依赖配置:
[package]
name = "hypercalc"
version = "0.1.0"
edition = "2021"
[lib]
name = "hypercalc"
crate-type = ["cdylib"]
[dependencies]
pyo3 = { version = "0.22", features = ["extension-module"] }
crate-type = ["cdylib"] 告诉 Cargo 编译为 C 兼容的动态链接库,这是 Python 能够加载的关键。
编写第一个 Rust 扩展函数
编辑 src/lib.rs,实现一个简单的双精度浮点平方根函数:
use pyo3::prelude::*;
/// 计算 x 的平方根
#[pyfunction]
fn sqrt(x: f64) -> PyResult {
if x < 0.0 {
return Err(PyErr::new::(
"Cannot compute square root of negative number"
));
}
Ok(x.sqrt())
}
/// Python 模块定义
#[pymodule]
fn hypercalc(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(sqrt, m)?)?;
m.add("__version__", env!("CARGO_PKG_VERSION"))?;
Ok(())
}
代码解析:
#[pyfunction]宏将 Rust 函数暴露为 Python 可调用函数PyResult<T>是 PyO3 提供的返回类型,自动将 Rust 错误转换为 Python 异常#[pymodule]定义 Python 模块入口,函数名必须与Cargo.toml中的name一致
构建并测试
在虚拟环境中执行开发构建:
maturin develop
编译完成后,立即在 Python 中测试:
>>> import hypercalc
>>> hypercalc.sqrt(2.0)
1.4142135623730951
>>> hypercalc.sqrt(-1.0)
Traceback (most recent call last):
...
ValueError: Cannot compute square root of negative number
进阶:定义 Python 类
PyO3 支持使用 #[pyclass] 和 #[pymethods] 定义完整的 Python 类。实现一个高性能的向量类:
use pyo3::prelude::*;
#[pyclass]
struct Vector {
#[pyo3(get, set)]
x: f64,
#[pyo3(get, set)]
y: f64,
#[pyo3(get, set)]
z: f64,
}
#[pymethods]
impl Vector {
#[new]
fn new(x: f64, y: f64, z: f64) -> Self {
Vector { x, y, z }
}
fn magnitude(&self) -> f64 {
(self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
}
fn normalize(&self) -> Self {
let mag = self.magnitude();
Vector {
x: self.x / mag,
y: self.y / mag,
z: self.z / mag,
}
}
fn dot(&self, other: &Vector) -> f64 {
self.x * other.x + self.y * other.y + self.z * other.z
}
fn cross(&self, other: &Vector) -> Vector {
Vector {
x: self.y * other.z - self.z * other.y,
y: self.z * other.x - self.x * other.z,
z: self.x * other.y - self.y * other.x,
}
}
fn __repr__(&self) -> String {
format!("Vector({:.2}, {:.2}, {:.2})", self.x, self.y, self.z)
}
}
在 Python 中使用:
>>> from hypercalc import Vector
>>> v = Vector(1.0, 2.0, 3.0)
>>> v.magnitude()
3.7416573867739413
>>> v.normalize()
Vector(0.27, 0.53, 0.80)
>>> v.cross(Vector(0.0, 1.0, 0.0))
Vector(-3.00, 0.00, 1.00)
性能对比:Rust vs 纯 Python
创建基准测试脚本 benchmark.py:
import time
import hypercalc
# Rust 版本
start = time.perf_counter()
for i in range(10_000_000):
_ = hypercalc.sqrt(i)
rust_time = time.perf_counter() - start
# Python 版本
import math
start = time.perf_counter()
for i in range(10_000_000):
_ = math.sqrt(i)
python_time = time.perf_counter() - start
print(f"Rust: {rust_time:.3f}s")
print(f"Python: {python_time:.3f}s")
print(f"加速比:{python_time / rust_time:.2f}x")
典型输出:
Rust: 0.523s
Python: 1.847s
加速比:3.53x
与 NumPy 集成
使用 ndarray 和 numpy crate 实现高效的数组运算:
# Cargo.toml 添加依赖
[dependencies]
ndarray = "0.15"
numpy = "0.22"
use ndarray::Array2;
use numpy::{IntoPyArray, PyArray2, PyReadonlyArray2};
use pyo3::prelude::*;
#[pyfunction]
fn matrix_multiply(
a: PyReadonlyArray2,
b: PyReadonlyArray2,
) -> PyResult>> {
let a_view = a.as_array();
let b_view = b.as_array();
let result = a_view.dot(&b_view);
Ok(result.into_pyarray(a.py()).to_owned())
}
Python 调用:
>>> import numpy as np
>>> from hypercalc import matrix_multiply
>>> a = np.random.rand(1000, 1000)
>>> b = np.random.rand(1000, 1000)
>>> c = matrix_multiply(a, b) # 比 np.dot 快 2-3x
异步支持:Rust Future 与 Python asyncio
PyO3 0.20+ 支持将 Rust async 函数暴露为 Python coroutine:
# Cargo.toml
[dependencies]
tokio = { version = "1", features = ["full"] }
use pyo3::prelude::*;
use tokio::time::{sleep, Duration};
#[pyfunction]
async fn async_fetch(url: String) -> PyResult {
// 模拟异步 HTTP 请求
sleep(Duration::from_millis(100)).await;
Ok(format!("Fetched: {}", url))
}
Python 使用:
>>> import asyncio
>>> from hypercalc import async_fetch
>>> async def main():
... result = await async_fetch("https://api.example.com")
... print(result)
>>> asyncio.run(main())
常见问题解答
PyO3 自动管理 GIL。Python 类型是 GIL 存在的证明,持有该类型的代码可以安全地操作 Python 对象。对于纯 Rust 计算(不涉及 Python 对象),可以在 py.allow_threads(|| { ... }) 块中释放 GIL,实现真正的并行。
使用 maturin develop 构建时添加 --features pyo3/extension-module,然后用 gdb 或 lldb 附加到 Python 进程。也可以在 Cargo.toml 中设置 profile.dev.debug = true 启用调试符号。
运行 maturin build --release 生成 wheel 文件,然后用 twine upload dist/*.whl 上传。Maturin 支持交叉编译,可为 Windows、macOS、Linux 一次性构建所有平台的 wheel。
PyO3 提供类型安全(Rust 编译器检查)、零成本抽象、优秀的 IDE 支持,并且 Rust 的内存模型避免了 Python C API 常见的引用计数错误。对于新项目,PyO3 是首选方案。
总结
通过本教程,你掌握了 2026 年最前沿的 Python 性能优化技术:
- ✓ 使用 Maturin + PyO3 快速搭建 Rust 扩展项目
- ✓ 编写高性能函数、类,并与 Python 无缝集成
- ✓ 与 NumPy、asyncio 等生态系统的深度整合
- ✓ 性能基准测试与生产环境部署
下一步:尝试将你的 Python 项目中的热点函数用 Rust 重写,体验 10 倍以上的性能提升!