惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Docker
Microsoft Azure Blog
Microsoft Azure Blog
云风的 BLOG
云风的 BLOG
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
LangChain Blog
P
Privacy & Cybersecurity Law Blog
Hugging Face - Blog
Hugging Face - Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
大猫的无限游戏
大猫的无限游戏
Cyberwarzone
Cyberwarzone
The Register - Security
The Register - Security
Stack Overflow Blog
Stack Overflow Blog
A
Arctic Wolf
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Threatpost
The GitHub Blog
The GitHub Blog
P
Privacy International News Feed
WordPress大学
WordPress大学
U
Unit 42
S
Securelist
T
The Exploit Database - CXSecurity.com
C
Cyber Attacks, Cyber Crime and Cyber Security
P
Proofpoint News Feed
Latest news
Latest news
Hacker News: Ask HN
Hacker News: Ask HN
小众软件
小众软件
Know Your Adversary
Know Your Adversary
The Cloudflare Blog
V
Vulnerabilities – Threatpost
The Hacker News
The Hacker News
Scott Helme
Scott Helme
有赞技术团队
有赞技术团队
Security Latest
Security Latest
Google DeepMind News
Google DeepMind News
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - Franky
Y
Y Combinator Blog
博客园 - 叶小钗
Security Archives - TechRepublic
Security Archives - TechRepublic
Google DeepMind News
Google DeepMind News
N
Netflix TechBlog - Medium
S
Secure Thoughts
T
Threat Research - Cisco Blogs
aimingoo的专栏
aimingoo的专栏
S
SegmentFault 最新的问题
Microsoft Security Blog
Microsoft Security Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
博客园 - 司徒正美
M
MIT News - Artificial intelligence

AirCloud 日常

快速生成 AI 应用的框架对比:Gradio、Streamlit 和 Dash Node.js 二进制打包:pkg 原理解析 - AirCloud 日常 基于 K8s 容器化运行 web 端对端测试 关于 JupyterLab cell 输出保持问题的设计方案 - AirCloud 日常 读完 type-challenges,我总结了如下常用的内容 - AirCloud 日常 基于 Container 架构的多框架前端应用 - AirCloud 日常 我们应该如何进行 Code Review ? - AirCloud 日常 Clean Code》读书笔记 - AirCloud 日常 使用 fst-json 自动生成更快的 json 序列化方法 《代码精进之路》与《代码整洁之道》-读书笔记 - AirCloud 日常 《重构》-读书笔记 - AirCloud 日常 《架构整洁之道》-读书笔记 - AirCloud 日常 React Conf 2021 内容概要 - AirCloud 日常 PC 开发技术选型:Electron 不是银弹 - AirCloud 日常 web 页面内存分析与生产环境禁用 console - AirCloud 日常 通过优化合成层优化性能 - AirCloud 日常 了解 StackOverFlow 上面最受欢迎的语言 Rust - AirCloud 日常 一些性能相关的 JavaScript 代码编写建议规范 - AirCloud 日常 如何让你的精力更多的用于提高技术深度 - AirCloud 日常
使用 Rust 开发 python 模块
2022-06-04 · via AirCloud 日常

关于 Rust 的基本介绍,我在之前的文章有做过一些总结。

本篇文章我们关注如何在 python 中调用 Rust 开发的模块。

Rust FFI 的一般思路

Rust 可以编译出兼容 C ABI 的动态库或者静态库,Rust 调用其他语言,以及 Rust 被其他语言调用,基本都是通过 C ABI 来进行 FFI 调用。

所以我们可以看出,实际上 C++ 调用 Rust 并不是特别方便,需要使用 Rust 提供的 C 接口,也因此没有办法使用 C++ 提供的类型,而 Rust 在导出接口的时候,也没有办法使用 Rust 的类型系统,需要转换成 C 类型。

大多数时候我们都会在这种场景下写一层 wrapper 和 converter,用来自动生成 FFI 层的一些胶水代码。

对于 Python 这类高级语言调用 Rust,基本也是类似的思路,我们可以简单总结为下图:

值得庆幸的是,对于 Python 调用 Rust,社区已经有非常多现成的成熟工具可以使用,基于这些工具,我们可以比较方便地专注于 Rust 实现逻辑本身,无需关注太多 FFI 和转换细节。

入门

一个比较方便的方法是使用 PyO3,PyO3 不仅仅提供了 rust binding,也提供了创建 python 包的开箱即用的脚手架工具 maturin,使用 maturin 我们可以很方便地创建一个基于 rust 开发的 python 扩展模块。

我们这里整理一下官方文档中提供的最简单的方式,读者可以直接依次执行下面的 shell 脚本:

1
2
3
4
5
6
7
8
9
10
$ mkdir string_sum
$ cd string_sum
# 创建 venv 的这一步不能省略,否则后续运行的时候会报错
$ python -m venv .env
$ source .env/bin/activate
$ pip install maturin
# 直接使用 maturin 初始化项目即可,选择 pyo3,或者直接执行 maturin init --bindings pyo3
$ maturin init
✔ 🤷 What kind of bindings to use? · pyo3
✨ Done! New project created string_sum

这个时候,我们可以得到一个简单的 Rust 项目,并且包含了一个示例调用,我们无需修改任何代码,可以直接执行下面的命令测试:

1
2
3
4
5
6
# maturin develop 会自动打包出一个 wheel 包,并且安装到当前的 venv 中 
$ maturin develop
$ python
>>> import string_sum
>>> string_sum.sum_as_string(5, 20)
'25'

进阶工具

接下来,我们介绍几个方便我们使用 Rust 开发 python 包的进阶工具或引导。

setuptools-rust

setuptools-rust 是一个 setuptools 的插件,让我们可以比较方便地编写使用 pyo3 开发的 rust python 包。

我们可以 clone 它的源代码,直接使用它提供的示例,参考如下命令测试:

1
2
3
4
5
6
7
8
9
$ cd examples/rust_with_cffi
$ python ./setup.py develop
$ python
Python 3.9.7 (default, Sep 3 2021, 12:37:55)
[Clang 12.0.5 (clang-1205.0.22.9)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from rust_with_cffi import rust
>>> rust.rust_func()
14

dict-derive

这个 rust 库提供了 FromPyObject 和 IntoPyObject 两个宏,使用这两个宏,我们可以很方便地进行 python dict 结构和 Rust 结构体的转换。

例如我们声明这样一个结构体:

1
2
3
4
5
6
#[derive(FromPyObject, IntoPyObject)]
pub struct User {
pub name: String,
pub email: String,
pub age: u32,
}

我们就直接可以在导出函数中这样使用了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

#[pyfunction]
fn get_contact_info(user: User) -> PyResult<String> {
Ok(format!("{} - {}", user.name, user.email))
}


#[pyfunction]
fn get_default_user() -> PyResult<User> {
Ok(User {
name: "Default".to_owned(),
email: "default@user.com".to_owned(),
age: 27,
})
}

我们通过宏展开可以发现,这两个宏所做的事情就是分别将 pyo3::types::PyDict 转换成 Rust 结构体和将 Rust 结构体转换成 pyo3::types::PyDict

整体宏展开的代码不多,还是比较方便阅读的。

rust-numpy

rust-numpy 是一个 rust 版本的 numpy C ABI 封装,使用这个库我们可以在 Rust 中调用 numpy

接下来我们运行该库的示例代码。

我们需要先安装 nox,nox 是一个 python 自动化任务工具。

1
$ python3 -m pip install nox

之后我们进入到命令行直接执行即可:

1
2
$ cd examples/simple
$ nox

顺利的情况下,我们可以看到它会输出测试成功:

1
2
3
4
tests/test_ext.py .....                                                                                                                                       [100

========================================================================= 5 passed in 0.32s =========================================================================
nox > Session tests was successful.

pandas

在 Rust 中并没有直接和 python 中的 pandas 包对标的诸如 pandas-rs 包。

不过 Rust 标准库本身也提供了非常多的数据处理函数如筛选、过滤等,我们可以自己手写代码完成大部分 pandas 的工作。

这篇文章中,作者使用了大约 160,000行/ 130列,总大小为 150Mb 的数据, 分别使用 Rust 和 Pandas 处理并测试,我们可以看到提升还是比较显著的:

Time(s) Mem Usage(Gb)
Pandas 3.0s 2.5Gb
Rust 1.6s 🔥 -50% 1.7Gb 🔥 -32%

其他

pyo3 的 README 里面还列举了一些其他的工具库,使用起来相对比较简单,这里就不做单独介绍了。

  • pyo3-log:在 Rust 中使用 python 的 logging 库。
  • pyo3-built:可以在编译 rust 的 python 模块的时候写入一些构建信息,如 rust 版本等。
  • pyo3-asyncio:python asyio 的 Rust binding,可以将 python 的 async 转换成 Rust 的 features。
  • rustimport:可以在 python 中直接引入 rust 代码,但因为引入的时候需要编译,笔者不是很建议在生产环境中直接使用。

虽然上面介绍了这么多工具,但是笔者认为,在实际使用中,还是远远不够的,我们应该还会结合业务,寻找和造出更多轮子,这部分工作就有待我们进一步开拓了。