楔子Rust 让 Python/ target=_blank class=infotextkey>Python 更加伟大,随着 Rust 的流行,反而让 Python 的生产力提高了不少 。因为有越来越多的 Python 工具 , 都选择了 Rust 进行开发,并且性能也优于同类型的其它工具 。比如:
- ruff:速度极快的代码分析工具,以及代码格式化工具;
- orjson:一个高性能的 JSON 解析库;
- watchfiles:可以对指定目录进行实时监控;
- polars:和 pandas 类似的数据分析工具;
- pydantic:数据验证工具;
- ......
因为通过 ctypes 调用动态库是最简单的一种方式 , 它只对操作系统有要求,只要操作系统一致,那么任何提供了 ctypes 模块的 Python 解释器都可以调用 。
当然这也侧面要求 , Rust 提供的接口不能太复杂,因为 ctypes 提供的交互能力还是比较有限的,最明显的问题就是不同语言的数据类型不同,一些复杂的交互方式还是比较难做到的,还有多线程的控制问题等等 。
之前说过使用 ctypes 调用 C 的动态库,里面详细介绍了 ctypes 的用法,因此本文关于 ctypes 就不做详细介绍了 。举个例子下面我们举个例子感受一下 Python 和 Rust 的交互过程,首先通过如下命令创建一个 Rust 项目:
cargo new py_lib --lib创建完之后修改 Cargo.toml , 在里面加入如下内容:[lib]# 编译之后的动态库的名称name = "py_lib"# 表示编译成一个和 C 语言二进制接口(ABI)兼容的动态链接库crate-type = ["cdylib"]cdylib 表示生成动态库 , 如果想生成静态库 , 那么就指定为 staticlib 。下面开始编写源代码,在生成项目之后,src 目录下会有一个 lib.rs,它是整个库的入口点 。我们的代码比较简单,直接写在 lib.rs 里面即可 。
#[no_mangle]pub extern "C" fn add(a: i32, b: i32) -> i32 { a + b}#[no_mangle]pub extern "C" fn get_square_root(v: i32) -> f64 { (v as f64).sqrt()}在定义函数时需要使用 pub extern "C" 进行声明,它表示创建一个外部可见、遵循 C 语言调用约定的函数,因为 Python 使用的是 C ABI 。此外还要给函数添加一个 #[no_mangle] 属性,让编译器在将 Rust 函数导出为 C 函数时,不要改变函数的名称 。确保在编译成动态库后,函数名保持不变,否则在调用动态库时就找不到指定的函数了 。
Rust 有个名称修饰(Name Mangling)的机制,在跨语言操作时,会修改函数名,增加一些额外信息 。这种修改对 Rust 内部使用没有影响,但会干扰其它语言的调用,因此需要通过 #[no_mangle] 将该机制禁用掉 。代码编写完成,我们通过 cargo build 进行编译 , 然后在 target/debug 目录下就会生成相应的动态库 。由于库的名称我们指定为 py_lib , 那么生成的库文件名就叫 libpy_lib.dylib 。
当功能全部实现并且测试通过时,最好重新编译一次,并加上 --release 参数 。这样可以对代码进行优化,当然编译时间也会稍微长一些,并且生成的库文件会在 target/release 目录中 。编译器生成动态库后,会自动加上一个 lib 前缀(windows 系统除外),至于后缀则与操作系统有关 。
- Windows 系统,后缀名为 .dll;
- macOS 系统,后缀名为 .dylib;
- linux 系统,后缀名为 .so;
import ctypes# 使用 ctypes 很简单,直接 import 进来# 然后使用 ctypes.CDLL 这个类来加载动态链接库# 或者使用 ctypes.cdll.LoadLibrary 也是可以的py_lib = ctypes.CDLL("../py_lib/target/debug/libpy_lib.dylib")# 加载之后就得到了动态链接库对象,我们起名为 py_lib# 然后通过属性访问的方式去调用里面的函数print(py_lib.add(11, 22))"""33"""# 如果不确定函数是否存在,那么建议使用反射# 因为函数不存在,通过 . 的方式获取是会抛异常的get_square_root = getattr(py_lib, "get_square_root", None)if get_square_root: print(get_square_root) """ <_FuncPtr object at 0x7fae30a2b040> """# 不存在 sub 函数 , 所以得到的结果为 Nonesub = getattr(py_lib, "sub", None)print(sub)"""None"""
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 你知道 Python 其实自带了小型数据库吗
- 解密Java连接MySQL的最佳实践:选择适合你的方式
- QQ如何用指纹解锁
- 怎么成为淘宝买菜的团长 如何申请成为淘宝买菜团长
- 如何制作三角形笔刷ps,ps该如何才可以画出三角形
- 在拼多多上如何修改评价,拼多多怎么修改评价等级
- cdr中应该如何画波浪线
- cdr2020如何合并打印,cdr该如何才可以进行打印
- 水泥路面起砂如何处理 水泥路面起砂如何处理视频
- 装修公司如何选 装修公司如何选好门店
