5

为何Rust并不适合服务端开发

 3 years ago
source link: http://mingplusplus.com/tech/2020/06/28/rust/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

为何Rust并不适合服务端开发

Jun 28, 2020

上个月我开启了一个新项目,抱着实验的心态用起了Rust,因为:

  • 社区里有很多人号称Rust is ready for web。
  • Rust连续若干年蝉联Stackoverflow上最受使用者欢迎的语言。

这篇小文总结了我最近对Rust的体验。 注:本文的评论仅对Rust 2020有效。

诚然,Rust并非浪得虚名,它的优点还是不少的。 在语言层面上,它对表达式的理解是进步的, 整体的语法是有很强的一致性,宏带来了足够的表达力,Trait的设计基本完善。 在工具链上,我个人很喜欢Cargo的体验,其对Monorepo的原生支持很赞。 Rustup也很方便。RLS有一些缺陷,但是基本上可以接受。 Rust编译器本身的错误提示不完美,但是每个错误都有对应的文章解释原因,让人印象深刻。 社区文化上,Rust社区对于文档的重视可以体现在它的血液里,发布package就自动生成文档网站真是一件非常方便和超前的事情, 非但如此,在文档中写的代码是被视为测试代码的存在,需要通过编译才可以发布,酷不酷? 另外,Rust的用户论坛上发问题得到回答的速度相当惊人的快,

然而,硬币总有两面,事实上我觉得Rust的体验在服务端开发的场景下并不友善,以至于使我不推荐它。

首先就是工程师的心智负担,完全消除GC是一个宏伟丰满的梦想,但我认为现实太骨感,用borrow/ownership的模式下有太多边际条件需要用奇怪的方法来解决。 其实在大部分程序里,这些边际条件都没什么太大的问题,但在服务端开发就不一样了。 比如Rust的闭包设计,Rust闭包允许用引用或者捕捉外部变量,这在通常情况下是可以的,但是在多线程的情况下,这种简单的模式就会出各种问题。 因为闭包本身的使用模式可以很丰富,一个闭包的生命周期可能会持续到程序的结尾,而它可能被多次调用,这时候,不论是“捕捉”还是“引用”都无法制作一个合适的闭包。 这个时候需要推出一个“拷贝”的闭包模式,但显然这个不是无代价的抽象,恐怕这几年都不会出现。 再比如因为Rust使用栈来管理变量的解构,使很多工具都用Drop来实现shutdown逻辑,然而这其实是个倒退,这降低了生命周期管理的粒度。 除此之外,你还可以经常看到'static在rust的工具里被过度使用,哪怕这完全是不需要的,感觉有削足适履的感觉。 从宏观来看,我认为GC还是利大于弊,尤其是在服务端应用里,遍地的堆内存状态。 我盼望如果能像是optional type一样,拥有Optional的No GC能力就好了。

另一大当前缺陷在我来看就是Rust的async和sync版本彼此不兼容以及async本身的不成熟。 现在基本没有争议的事是,在普遍的场景下async(用户空间轻量级进程)的性能更好。 Rust的async feature是在去年才引入stable的,由于不兼容sync,现在Rust的Web社区基本分为了两派,async和sync,这是一个很无奈的状况。 很多积攒多年的工具都是基于sync来做的,一下子引入的async之后,这些工具都得被迫大重构,而且还得被迫放弃一半community。 因此作为工具作者基本处于两难的状况。 然而如果async Rust本身足够成熟,这问题也不会那么严重,我认为现在一个很大的问题是Rust无法在不依赖特定runtime的情况下spawn async task, 详见这里这里。 这个问题可能(已经)会导致更大的分裂,也催生了些奇趣的工具。 有时候我想,如果把Rust sync和Rust async都视为一种Runtime,尽可能实现同构的API,是否就可以让世上出现兼容sync和async的工具框架? 不管如何,直到Rust async成熟,要想有好体验估计还有很久。

最后就是一些细枝末节的细节:

  • 指针类型具有特别的casting能力,但是文档没有明确指出。
  • 很多一些所谓高级的语言内容,Unpin/Pin以及Exterior Mutability,UnwindSafty,都是很容易遭遇的概念,然而很多遭遇都是被动遭遇,这对开发体验影响很大。
  • 工具多样性,Rust还是缺一些web的必要工具,比如针对中大型项目的IoC/DI框架。
  • Async Rust无法访问调用栈的上下文,这把一些很重要的动态功能给挡在了门外,例如根据根据上下文来创建日志。
  • 缺乏一个正常的的union type,感觉这是从Haskell里学来的坏东西。
  • 社区过度依赖宏。
  • 对编译时间的控制非常困难,稍有不慎项目的编译时间就会skyrocket。

由于以上诸多缺点,我也许不会继续使用Rust在我的项目里,但尽管如此,我还是在长期来看还是很看好Rust的。 正是因此我制作了Sai,希望能弥补社区的空白, 并且也许能帮助到想用Rust来开发大规模服务端程序的开发者。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK