rustimport:使用 Rust 加速 Python 的最简单方法


如果你想加速一些现有的 Python 代码,用 Rust 编写编译扩展可能是一个很好的选择:

  • 在许多情况下,Rust 代码的运行速度比 Python 快得多。
  • Rust 可以防止 C、C++ 和 Cython 代码中经常出现的大多数内存管理错误。
  • 可用的第三方 Rust 包生态系统正在不断增长,与 C 和 C++ 不同,它还有内置的包管理器和构建系统。

rustimport是一个库,它可以轻松地在 Python 中导入导入独立的 Rust 文件(目前仅在 Linux 和 macOS 上)。

先决条件
rustimport动态编译 Rust 代码,因此您需要在计算机上安装 Rust 编译器。这不是您最终打包的库或应用程序想要的,但我们的用例是原型设计,无论如何您都需要编译器。

您还需要进行rustimport安装,例如pip install rustimport在 virtualenv 或 Conda 环境中运行。

Rust 中实现斐波那契数列:

// rustimport:pyo3

// PyO3 is a Rust library for writing Python extensions;
// we'll import its most commonly used APIs. 
rustimport自动为你导入pyo3
use pyo3::prelude::*;

#[pyfunction]  //暴露函数给Python
fn fibonacci(number: u64) -> u64 {
    if number == 0 {
        return 0;
    }
    if number == 1 {
        return 1;
    }
    let mut prevprev = 0;
    let mut prev = 1;
    let mut current = 1;
    for _ in 0..(number - 1) {
        current = prevprev + prev;
        prevprev = prev;
        prev = current;
    }
    current
}

rustimport可以让你导入 Rust 文件;你所要做的就是import rustimport.import_hook:

In [2]  import rustimport.import_hook

In [3]: from rustfib import fibonacci
    Updating crates.io index
  Downloaded proc-macro2 v1.0.64
  Downloaded 1 crate (44.8 KB) in 0.32s
   Compiling target-lexicon v0.12.8
   Compiling autocfg v1.1.0
...
   Compiling pyo3-macros v0.18.3
   Compiling rustfib v0.1.0 (/tmp/rustimport/rustfib-7eb3578b36e7d1e44917eae13823c3f8/rustfib)
    Finished dev [unoptimized + debuginfo] target(s) in 10.13s
In [4]: fibonacci(50)
Out[4]: 12586269025

我们刚刚导入了一个 Rust 文件,它会自动编译,然后我们运行代码!
如果我们查看目录中的文件,我们可以看到创建了一个新的已编译的 Python 扩展:

$ ls
rustfib.cpython-311-x86_64-linux-gnu.so  rustfib.rs

此时我们不需要导入rustimport.import_hook:我们可以只导入扩展,因为它已经编译了:

$ python -c "import rustfib; print(rustfib.fibonacci(10))"
55

工作方式
rustimport以多种不同的方式减少您的努力。
首先,rustimport.import_hook将挂接到Python的导入系统;当它看到具有相关名称的 Rust 文件时,它会将其编译为 Python 扩展,然后导入它。为了防止您随机导入现有的任何 Rust 文件,您需要在文件顶部添加特殊注释:
// rustimport:pyo3

其次,用 Rust 编写 Python 扩展的典型方式是使用名为PyO3的第三方库。在正常的 Rust 设置中,您必须添加pyo3依赖项;
而上面代码中 // rustimport: pyo3告诉你rustimport自动为你做这件事。

第三,一个普通的PyO3扩展需要你有一个模块初始化函数,在这里你需要注册函数。在我们的例子中可能是这样的

// This is optional if you're using rustimport:
#[pymodule]
fn rustfib(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(fibonacci, m)?)?;
    Ok(())
}

rustimport 会自动为您生成这些代码。如果#[pyfunction]和#[pyclass]的默认支持不够,您可以自己编写。

第四,你不需要编写或生成Cargo.toml文件,大多数Rust包都需要。