Rust 语言从入门到实战
唐刚
Rust 语言中文社区联合创始人
5266 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 36 讲
Rust 语言从入门到实战
15
15
1.0x
00:00/00:00
登录|注册

30|Unsafe编程(下):使用Rust为Python写一个扩展

你好,我是 Mike。
上一讲我们了解了 Unsafe Rust 的所属定位和基本性质,这一讲我们就来看看 Rust FFI 编程到底是怎样一种形式。
FFI 是与外部语言进行交互的接口,在 Safe Rust 看来,它是不可信的,也就是说 Rust 编译不能保证它是安全的,只能由程序员自己来保证,因此在 Rust 里调用这些外部的代码功能就需要把它们包在 unsafe {} 中。
Rust 和 C 有血缘关系,具有 ABI 上的一致性,所以 Rust 和 C 之间可以实现双向互调,并且不会损失性能。

Rust 调用 C

我们先来看在 Rust 中如何调用 C 库的代码。
一般各个平台下都有 libm 库,它是操作系统基本的数学 math 库。下面我们以 Linux 为例来说明。下面的示例代码来自 Rust By Example
use std::fmt;
// 连接到系统的 libm 库
#[link(name = "m")]
extern {
// 这是一个外部函数,计算单精度复数的方根
fn csqrtf(z: Complex) -> Complex;
// 计算复数的余弦值
fn ccosf(z: Complex) -> Complex;
}
// 对unsafe调用的safe封装,从此以后,就按safe函数方式使用这个接口
fn cos(z: Complex) -> Complex {
unsafe { ccosf(z) }
}
fn main() {
// z = -1 + 0i
let z = Complex { re: -1., im: 0. };
// 调用m库中的函数,需要用 unsafe {} 包起来
let z_sqrt = unsafe { csqrtf(z) };
println!("the square root of {:?} is {:?}", z, z_sqrt);
// 调用安全封装后的函数
println!("cos({:?}) = {:?}", z, cos(z));
}
// 用 repr(C) 标注,定义Rust结构体的ABI格式,按C的ABI来
#[repr(C)]
#[derive(Clone, Copy)]
struct Complex {
re: f32,
im: f32,
}
// 实现复数的打印输出
impl fmt::Debug for Complex {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.im < 0. {
write!(f, "{}-{}i", self.re, -self.im)
} else {
write!(f, "{}+{}i", self.re, self.im)
}
}
}
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了使用Rust编写Python扩展的关键内容,重点讨论了在Rust中调用C库的方法以及Rust给Python编写扩展的基本思路和相关工具。文章首先介绍了在Rust中调用C库的方法,包括使用`extern`关键字导入外部函数、定义C语言结构体的Rust表示以及使用`unsafe`包裹调用外部函数的示例。接着介绍了Rust官方项目bindgen,可以从C库的头文件生成Rust FFI绑定层代码,简化了转换过程。然后,文章讨论了在C中调用Rust代码的基本思路,以及如何使用Rust给Python编写扩展。最后,文章提到了PyO3项目,可以帮助减轻编写Rust扩展的痛苦,自动处理中间样板封装过程。此外,还介绍了PyO3的性能优化示例和业界知名PyO3绑定项目。整体来看,本文涵盖了Rust与C的交互、Rust给Python编写扩展的基本思路和相关工具,对于想要了解这方面内容的读者来说,是一篇值得阅读的技术文章。文章通过示例展示了在Rust中调用C函数、在C函数中调用Rust函数,以及在Python中调用Rust实现的模块和函数。并且通过对比Rust的实现版本与Python原生的实现版本,发现使用Rust写Python扩展性能更好。 Unsafe Rust编程大量出现在底层性能的优化和与其他语言交互的场景中,体现了Rust语言对安全性和性能的追求。文章还提到了Unsafe Rust编程可以赋能其他语言社区,将Rust的澎湃动力和安全扩展到了Python、JavaScript等其他语言。文章鼓励读者踏上安全提升和性能提升之路,有Rust为你输出动力,保驾护航,你便可以放开手脚,大胆去干。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Rust 语言从入门到实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(9)

  • 最新
  • 精选
  • 小可爱(`へ´*)ノ
    跟完了,很值得的,老师功底很厚。

    作者回复: 谢谢

    2024-03-08归属地:重庆
  • A0.何文祥
    老师,我根据文档https://pyo3.rs/v0.20.2/parallelism了解到,如果要在PyO3里Release GIL需要执行Python::allow_threads,咱们实例是不是遗漏了这一步,实际跑的还是single CPU core。

    作者回复: 我给的源代码里面有这个功能,注释掉了。你可以研究研究。关闭的原因是为了简化难度。

    2024-01-31归属地:广东
  • tan
    window 观测时间: Measure-Command {python .\fib_rust.py} 。 ps: 为什么我在window10上测试 python自己写的函数只要 0.49s, 调用rust的需要12s ps: 如果有同学不关心执行时间想要确定调用成功与否,需要`calc_fib` 把给这个函数返回值

    作者回复: 这种观测不准,因为混杂了加载文件的时间在里面。不过那个12秒多的差距有点吃惊了。你开了release编译没

    2024-01-20归属地:中国香港
  • zxk
    C 语言中的 char 是一个 8bit 大小的类型,一个 char 可以覆盖 ASCII 码表;而在 Rust 中 char 是一个 Unicode 字符,使用 32bit(即 UTF-32)进行存储。 C 语言中的字符串其实就是一个 char 数组,并以 `\0` 作为结束标志;而 Rust 中的 String 是经过 UTF-8 编码后的字节数组,一个实际的字符对应一个或多个字节(UTF-8 是可变长编码),通过一个长度来得出字符串的结束位置。 若要将 C 语言的字符串类型映射到 Rust 中的类型,目前能想到两种方案: 1. C 端以 UTF-8 的方式编码存储字符串,并传递给 Rust; Rust 可以选择使用 CString 存储在转化,或者自行解析并注意 `\0` 的标识符; 2. C 端自由选择编码,在传给 Rust 时告诉 Rust 编码方式,并由 Rust 自行解码,并转为内部的 UTF-8 编码。

    作者回复: 真棒👍!

    2024-01-20归属地:海南
  • Noya
    完结!

    作者回复: 真棒👍

    2024-01-04归属地:浙江
  • 刘丹
    请问在 calc_fib 函数里,为什么 fib 的计算结果被丢弃,而返回 Ok(()) 呢?

    作者回复: 只是一个示例,这里只是为了比较一下计算性能。你可以尝试改进一下这个示例。👍

    2024-01-01归属地:广东
    2
  • 刘丹
    请问老师,pyproject.toml 这个文件是哪个工具需要的? 我按本课教程操作,没有创建这个文件也能正常运行。

    作者回复: 这个工程文件是 maturin 创建的 . 没有创建这个文件也能正常运行, 我还没试过. 可能maturin能识别默认配置吧.

    2024-01-01归属地:广东
    3
  • Geek_72807e
    基本跟完了老师的课程,还有哪些进阶内容或参考资料老师推荐一下?!

    作者回复: 陈天老师的课,教你完整地做一个kv db. 挺不错的. 陈老师的课可以看作是本课程的进阶课程.

    2024-01-01归属地:山西
    2
  • 一带一路
    Rust 与 Python 绑定未来可期!

    作者回复: 未来可期!

    2024-01-01归属地:四川
收起评论
显示
设置
留言
9
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部