简单说一下吧,python 语言效率的问题也是老生常谈了,我也是 v2 上 py 社区的老面孔了
rust 这门语言我没接触过,我对他的印象一直是那种想要干掉老语言的新语言,但是生态不行所以没戏。印象中 rust 是对标 c/c++,scala 对标 java,julia 对标 python,再加一个专门写网络服务的 go,这似乎就是新时代的样貌了。但是其实这四门语言除了 go 以外都几乎没接触过。
直到前几天跟朋友聊天,对方偶然说起 python 调用 rust 可以是一种解决方案。我正好也面临计算密集任务的困扰,就去搜了一下,一搜,发现据说很香,于是试用了一下,发现真的很香,一直香到爆炸了,我就来 v2 发帖了。
=================================
先说一下直观效果,团队现在在做数据类服务,有很多密集计算型任务,并且以后可能越加越多。刚开始写的时候肯定是 python 实现算法,但是随着数据量增多,算法变复杂,处理时间成几何倍数增加,py 已经顶不住了。所以我们之前是把一些最集中的部分先用 c++抽出来写成插件,因为我和另外一个朋友都能写点简单的 c++,这么暂时先凑合着,原计划是要用 cython 把算法部分完全重写的。
前天听说 rust 能用,当天花了几个小时过了一遍 rust 的语法,昨天把 c++的东西用 rust 完全重写了一遍,大概一千多行,今天已经上测试服务器了。并且简单跑了一下分,rust 嵌入 python 表现非常优秀。
我们重复执行同一个计算任务,原任务用 python 实现大概耗时在一分多钟,切换到 c++之后大概耗时在 3100 毫秒,今天改写成 rust 之后,在实现基本上完全相同的情况下,单次执行时间缩短到了 2300 毫秒左右,令人很惊喜。
而之后多线程压力测试中,1600 次任务,c++版本耗时 720 秒,rust 版本耗时 440 秒。这个差距相对于单核进一步拉大,似乎数据中转和线程调度上,相对于 cython 还有进一步的优势。
=================================
所以我在这里向所有在 python 任务中遇到 cpu 密集型任务瓶颈的朋友们推荐 rust 这门语言和它配套的 python 嵌入方案。目前看来几天的使用里,它可能带来的问题并不多。我们测试中遇到的为数不多的问题是似乎底层调用机制与 cython 的嵌入不同。单纯测试空函数返回时间,如果使用 cython 编译 python 函数,是可以加速函数返回的,但使用 rust 嵌入方案的话却会让返回时间减慢一倍左右。我个人也不是很了解解释器调用的实现细节,这个暂且不谈。不过只要不做特别细粒度的嵌入,这其实也不会造成什么困扰。
而与问题相对的,好处就很多了。
rust 的好处其一是它的性能强,与原生 C 比肩,并且显然在实际生产中比 c 更快。因为一般用 c++也就是用 stl 中的容器和算法搞一搞,我个人比较菜,不太有水平自己实现。在这种条件下,rust 的内置实现的几种数据结构和算法,是比 c++stl 更快的,起到了实际上性能领先的作用。
其二是 rust 的学习曲线非常平滑,本身通过限制语法自由度,在设计上屏蔽了 c++中一些让人非常头秃的一些特性(野指针之类的),加上有比较完善的内建通用数据结构,导致如果你只是单纯的实现算法的话,向我们一样简单学习几小时就直接可以工作了。并且同样由于编译器要求严格,你写出的代码只要能过编译,一般质量都还可以。
第三是 rust 的工程化很香。之前用 cython 方案,其实整个目录结构工程化不是很好做,因为 cython 这门介于 c 和 py 之间的语言,说不好听点是四不像,很多似是而非的坑需要自己踩,通常是 c 的方法也不行,py 的方法也不行,只能按照 cython 独有的规矩。这点切换到 rust 之后就不构成烦恼,因为原生模块化方案还不错,嵌入 py 时可以非常接近 py 工程目录的逻辑结构,整个代码解耦非常舒服。
第四是 rust 这门语言描述能力比较强,毕竟是一门十年左右的新语言,在编程语言大家庭中算孙子辈的了。像我们平常使用 python 的原因之一可能就是因为 py 的描述能力强大,相比之下如果用纯 c 语言写东西的话就会感觉在描述能力上束手束脚。而切换到 rust 则不会有明显的不适感,虽然相对于动态的 python 确实受到了诸多限制,但是本身语言也吸收了这么多年优秀语言的优秀特性,也加入了很多语法糖,比如下述代码实现的逻辑
fn main() {
let list = vec![1 , 2 , 3 , 4 , 5];
for i in 0..list.len() {
println!("num: {}" , list[i])
}
}
即使你从未学习过 rust 的代码,你也会发现基本上能看懂,并且这种语言在基础使用场景的描述能力并不弱,已经十分接近自然语言逻辑。
======================================
总之胡言乱语写了这么多,与大家分享,已经很熟悉这套工具链的朋友请勿喷,我相信还有很多和我一样不了解的朋友,欢迎探讨,我们共同进步。
1
shoaly 2021-03-01 12:25:31 +08:00
越来越多的场景 会是多语言互相 协同, 利用各自优势吧...
|
2
shoaly 2021-03-01 12:45:49 +08:00
对了 ,老哥有没有比较过 rust 和 go 的时间
|
3
jokaye 2021-03-01 12:58:14 +08:00
for i in 0..list.len() —— 哎这语法糖一言难尽
|
4
LeeReamond OP @shoaly 我不会用 python 调 go,没研究过。不过单纯语言性能的话你可以在网上搜到其他的跑分。一般来说同样逻辑 rust 肯定比 go 快,可能快几到几十百分点这样,没有数量级差距。因为 go 有 gc 而 rust 没有,但是 rust 香就香在它没有 gc 一样做到了你开发时候不需要自己考虑回收的问题
|
5
LeeReamond OP @jokaye 挺好的啊,不知道有啥一言难尽的,我写了一千行 rust 以后感觉挺香的。毕竟 for 太常用了,像 js 那种进入 es6 以后 for 的语法大幅简化,但还是要比这种写法多写不少字。rust 这个语法的优化接近 python 了,你甚至不需要考虑 i 从哪来的问题,写码的时候能体会到一种显著的对心智负担的降低
|
6
itskingname 2021-03-01 13:39:54 +08:00
@shoaly Python 调用 Golang 可以看这篇文章: https://mp.weixin.qq.com/s/H1Fe7BXdKIeEzIxjLxlYBg
|
7
Kilerd 2021-03-01 15:33:34 +08:00
要不是看到这 for i in 0..list.len(), 我差点就以为你懂 rust 了。
|
8
liprais 2021-03-01 15:35:46 +08:00 1
我猜你的 python 算法肯定是 numpy 和原生类型混用的
|
9
wzb0909 2021-03-01 15:50:58 +08:00
|
10
Jirajine 2021-03-01 16:05:51 +08:00 via Android
rust 对标 cpp,提供零运行时开销的、尽可能多的抽象和各种特性。
julia 对标 c,保持简单、手动内存管理、无宏、无隐式的调用和分配。 |
11
joApioVVx4M4X6Rf 2021-03-01 20:25:57 +08:00
话说 python 怎么和 rust 通信的呀,可以发个链接学习学习吗
|
12
hsfzxjy 2021-03-01 21:33:41 +08:00 via Android
楼主是用 pyo3 吗
|
13
LeeReamond OP |
14
runstone 261 天前
楼主用的 pyo3 去结合的么?还是别的什么工具。这里面需要注意的是 python 的整数和 float 都是无穷大的,对应 rust 没有相应的类型啊,要怎么搞?
|