厌倦了C++,CS&ML博士用Rust重写Python扩展,还总结了9条规则

选自medium.com

作者: Carl M. Kadie

机器之心编译

编辑:杜伟、陈萍

效果好不好,试一试就知道了。

Python 是数据科学家最流行的编程语言之一,其内部集成了高质量分析库,包括 NumPy、SciPy、自然语言工具包等,这些库中的许多都是用 C 和 C++ 实现的。

然而,C 和 C++ 兼容性差,且本身不提供线程安全。有研究者开始转向 Rust,重写 C++ 扩展。

拥有 CS 与机器学习博士学位的 Carl M. Kadie ,通过更新 Python 中生物信息学软件包 Bed-Reader,为研究者带来了在 Rust 中编写 Python 扩展的九个规则。以下是原博客的主要内容。

一年前,我厌倦了我们软件包 Bed-Reader 的 C++ 扩展,我用 Rust 重写了它,令人高兴的是,得到的新扩展和 C/C++ 一样快,但具有更好的兼容性和安全性。一路走来,我学会了这九条规则,可以帮助你创建更好的扩展代码,这 九条规则 包括:

1. 创建一个包含 Rust 和 Python 项目的单独存储库

2. 使用 maturin & PyO3 在 Rust 中创建 Python-callable translator 函数

3. 让 Rust translator 函数调用 nice Rust 函数

4. 在 Python 中预分配内存

5. 将 nice Rust 错误处理翻译 nice Python 错误处理

6. 多线程与 Rayon 和 ndarray::parallel,返回任何错误

7. 允许用户控制并行线程数

8. 将 nice 动态类型 Python 函数翻译成 nice Rust 泛型函数

9. 创建 Rust 和 Python 测试

其中, 文中提到的 nice 这个词是指使用最佳实践和原生类型创建 。换句话说:在代码顶部,编写 nice Python 代码;在中间,用 Rust 编写 translator 代码;在底部,编写 nice Rust 代码。结构如下图所示:

上述策略看似显而易见,但遵循它可能会很棘手。本文提供了有关如何遵循每条规则的实用建议和示例。

我在 Bed-Reader 进行了实验, Bed-Reader 是一个 Python 包 ,用于读取和写入 PLINK Bed Files,这是一种在生物信息学中用于存储 DNA 数据的二进制格式。Bed 格式的文件可以达到 TB。Bed-Reader 让用户可以快速、随机地访问数据的子集。它在用户选择的 int8、float32 或 float64 中返回一个 NumPy 数组。

我希望 Bed-Reader 扩展代码具有以下特点:

  • 比 Python 快;

  • 兼容 NumPy;

  • 可以进行数据并行多线程处理;

  • 与执行数据并行多线程的所有其他包兼容;

  • 安全。

我们最初的 C++ 扩展兼具速度快、与 NumPy 兼容,以及使用 OpenMP 进行数据并行多线程等特点。遗憾的是,OpenMP 运行时库 (Runtime library),存在 Python 包兼容版本问题。

Rust 提供了 C++ 扩展带来的优势。除此之外,Rust 通过提供没有运行时库的数据并行多线程解决了运行时兼容性问题。此外,Rust 编译器还能保证线程安全。

在 Rust 中创建 Python 扩展需要许多设计决策。根据我使用 Bed-Reader 的经验,以下是我的使用规则。 

规则 1:创建一个包含 Rust 和 Python 项目的单独存储库

下表显示了如何布局文件:

使用 Rust 常用的‘cargo new’命令创建 Cargo.toml 和 src/lib.rs 文件。Python 没有 setup.py 文件。相反,Cargo.toml 包含 PyPi 包信息,例如包的名称、版本号、 README 文件的位置等。要在没有 setup.py 的情况下工作,pyproject.toml 必须包含:

[build-system]
requires = ["maturin==0.12.5"]
build-backend = "maturin"

一般来说,Python 设置在 pyproject.toml 中(如果不是,则在 pytest.ini 等文件中)。Python 代码位于子文件夹 bed_reader 中。

最后,我们使用 GitHub 操作来构建、测试和准备部署。该脚本位于 .github/workflows/ci.yml 中。

规则 2:使用 maturin & PyO3 在 Rust 中

创建 Python-callable translator 函数

Maturin 是一个 PyPi 包,可通过 PyO3 构建和发布 Python 扩展。PyO3 是一个 Rust crate,用于在 Rust 中编写 Python 扩展。

在 Cargo.toml 中,包含这些 Rust 依赖项:

[dependencies]
thiserror = "1.0.30"
ndarray-npy = { version = "0.8.1", default-features = false }
rayon = "1.5.1"
numpy = "
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值