最近在学习Rust,这是一门系统级语言。保证安全的同时摆脱了GC, 它很香同时也很难上手, 刚学完一点皮毛知识决定做个小玩意儿玩玩,是骡子是马总要拉出来溜溜~

目前个人认为Rust在性能上是可以和C++媲美的一门语言,既然如此那就用它来为Python加个速吧!😊

起步准备

Python加速与写C语言扩展类似,最终通过pyd来调用。在此之前我们用到Rustpyo3库,另外我们编写的是一个lib而不是应用程序,因此我们要创建lib项目。

创建lib库项目:

$ cargo new <project name> --lib

Cargo.toml 文件添加pyo3依赖:

1
2
3
4
5
6
7
[lib]
name = "string_sum"
crate-type = ["cdylib"]

[dependencies.pyo3]
version = "0.15.1"
features = ["extension-module"]

一个小Demo

使用文档的例子,编写一个Hello World试试,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use pyo3::prelude::*;

/// Formats the sum of two numbers as string.
#[pyfunction]
fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
Ok((a + b).to_string())
}

/// A Python module implemented in Rust.
#[pymodule]
fn string_sum(py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
m.add_function(wrap_pyfunction!(test_func, m)?)?;

Ok(())
}

然后用打包命令将这个项目build一下:
$ cargo build --release

这时候应该能看到项目的结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
.
├─src
└─target
├─release
│ ├─.fingerprint
│ ├─build
│ ├─deps
│ ├─examples
| ├─string_sum.dll
| ├─string_sum.d
| ├─libstring_sum.dll.a
│ └─incremental
└─rls

这里的string_sum.dll就是我们需要的,我们将文件的扩展名改成pyd即可得到我们的python扩展文件 -> string_sum.pyd

完成之后尝试一下调用这个文件,新建一个test文件夹并将其复制进去, 最后调用一下:

1
2
3
4
import string_sum
print(string_sum.sum_as_string(200, 33))

# export: 233

CPU运算性能Demo

继续在刚刚的文件中添加一个需要大量计算的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
...
#[pyfunction]
fn test_func() -> PyResult<String> {
for a in 0..10 {
for b in 0..10 {
for c in 0..10 {
for d in 0..10 {
for e in 0..10 {
for f in 0..10 {
if m(a) + m(b) + m(c) + m(d) + m(e) + m(f)
== a * 10_0000 + b * 1_0000 + c * 1000 + d * 100 + e * 10 + f
{
println!("{}{}{}{}{}{}", a, b, c, d, e, f);
}
}
}
}
}
}
}
return Ok(String::new());
}

/// A Python module implemented in Rust.
#[pymodule]
fn string_sum(py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(test_func, m)?)?;

Ok(())
}

后续的步骤与上面一致,编译重命名后拷贝到python目录下,修改一下刚才的python代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import string_sum
import time

def target_func():
def m(x):
return x * x * x * x * x

for a in range(0,10):
for b in range(0,10):
for c in range(0,10):
for d in range(0,10):
for e in range(0,10):
for f in range(0,10):
if m(a) + m(b) + m(c) + m(d) + m(e) + m(f) == a * 10_0000 + b * 1_0000 + c * 1000 + d * 100 + e * 10 + f:
print(f"{a}{b}{c}{d}{e}{f}")



def test_fun(func, flage:str = "Python"):
"""计时函数

Args:
func (function): 回调函数

"""
start = time.time()
func()
end = time.time()
print(f"{flage} time: ",end - start)
return start - end

# 开始计时 -> Rust
rust_time = test_fun(string_sum.test_func, flage="Rust")

# 测试纯Python
python_time = test_fun(target_func)

print(f"Rate: {python_time/rust_time}")

运行看一下结果,从结果看到RustPython足足快了125倍多!!!