Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
1 contributor

Users who have contributed to this file

76 lines (41 sloc) 15.7 KB

原文: (Englisth) http://www.viva64.com/en/b/0324/ (Russia) http://eax.me/cpp-will-never-die/ 翻译者: Scott Huang
日期: August 23,2015 于 厦门

#批判Rust语言,以及C/C++为什么永远不会死

12.05.2015Eax Melanhovich

(译者缩写了该段)原文是俄语,有人感兴趣,得到作者同意后,把它翻成英文。(译者:然后我再把它翻成中文。)

(译者缩写了该段)我不能不注意到这篇博客的读者有多大兴趣。显而易见,这篇博文将会导致一场语言大圣战,所以,请三思而后行,确定你将会通过发表“有建设性”的评论参与讨论后再开始阅读这篇文章。

再次说明原文是俄语:) (Russia) http://eax.me/cpp-will-never-die/

##注: 进一步讲,我冒昧的假设Rust有意尝试创建一个快速并且安全的语言。 毕竟,Mozilla的人最初构思用它作为工具来开发一个浏览器引擎。如果它被证明是另外一个仅仅安全的语言,那么我就不可能得到全部东西。 有很多非常不同的安全语言供人们选择和品味,如果Rust没有打算代替C++,那么 (1)为什么它需要包含一个不安全子集; (2)并且,为什么作者要抛弃Rust的轻量级进程?毕竟它们很方便,对吧?换句话说,如果我假设错了,那么整件事情就没有讨论的意义了。

如有你碰巧偶尔逛逛linux.org.ru论坛,那么请被警告到这篇文章没有触及为什么不喜欢Rust的那10条纯技术理由。和亲爱的伙伴 @sum3rman的Skype对话已经显示有一个以上的意见说那太“技术性”了。所以,我不得不承认,我下面罗列的东西不讨人喜欢,但是我还是冒险从中引用一些最有趣的条款在这里。实际上,一些普通常识性的理由足以不用触及技术性的讨论。

每一个理智的程序员都非常清楚的知道C/C++在最近的将来不会死掉。没有人会尝试用新语言重新编写几乎所有已经存在的桌面应用程序,操作系统内核,编译器,游戏以及浏览器引擎,虚拟机,数据库,压缩工具,音视频编码解码器,以及一堆其他的C库等等。 这是一批数量巨大的快速的、调试过的被时间证明了的代码。重写的代价太过昂贵和太冒险了,并且,诚实的讲,除了一些疯狂的Rust粉丝,没人会认为这有意义。 对C/C++程序员的需求从来都是高的,并且将保持很长一段时间。

好吧,那就用Rust写一些新的代码吧?

你可能还记得,这并不是第一次尝试创造一个“更好的”C/C++。 拿D语言来举例。它在2001年发布,且确实是一个好的语言。但没有空间发展,没有像样的开发工具,没有著名的成功案例可以联想到它。OpenMW项目最初用D开发,但作者突然决定用C++从头重写。据他们承认,他们收到一大堆的邮件说,“你们创建了一个很酷的项目,我们想做贡献,但是我们不懂,也不喜欢学习这个愚蠢的D语言”。维基百科告诉我们,除了D,还有有其它尝试准备杀死C++ - 举例说 Vala, Cyclone, Limbo, Bitc。 你们中有多少人曾经听说过这些语言?

我觉得人们是时候必须从历史中得到教训了。没有一个理智的人会在他们的项目中开始使用一个新语言,直到你给他们一些非常酷的开发支持工具,告诉他们一些成功故事,并且证明一堆程序员靠这个语言做日常工作维持生活。作为程序员,他们从来不会 - 除了一些最年轻的人 - 花他们的时间和健康来学习另外一种“非常棒”的语言,直到你展示一些非常酷的开发工具(不是未完工的像Racer工具那样)和许多确实准备好的库(不是“实验性的”或者“不稳定的”东西),告诉他们一些成功案例,告诉他们有许多空缺在他们的城市或乡镇。你知道,这就像“鸡和蛋”的两难处境。只有非常少的机会,这个问题确实得到解决(最近相关的案例是Go和Scala) - 这得感谢一些大公司(Google,Typesafe)的时间和金钱投入,他们基于一些原因推广一个新语言。

正如我提到的,有许多非技术性的理由单独就可以质疑Rust。但是,让我们假想一会儿这些理由都不存在。然后没有理由不用Rust写程序,对不对?嗯,这也是很值得商榷的,至少可以说。

C/C++因各种原因而受到批判。顺便说一下,大多数批评者还从来没有看过产品级的C++代码。简短的说,C++的问题是非常快(并且只要求一点点内存,电量,等等),但是从允许数组越界,自由的存取内存等方面看不够安全。过去,这个问题促使程序员们开发出一系列安全的语言,比如Java,C#,Python还有其他等等。但是,他们被证明和C++相比,对资源需求太多,同时还有其他一些不足 - 比如, 比如当进行垃圾回收时“停止世界”问题。这也是为什么程序员正努力创建一个和C++一样快,但安全的语言。Rust是其中的候选人之一。

Rust确实是安全的,但是,不幸的是,远没有快速。在写这篇文章的时候,它和Java,go和Haskell的性能如下图所示:http://www.viva64.com/media/images/content/b/0324_Criticizing-Rust-Language-Why-Cpp-Will-Never-Die/image1.png

Picture 1

我真诚的希望程序员找到一个方法来加速它的时间,但在那之前,它没有比Scala或者Go花更多时间从安全/速度角度进行妥协。是否可以使一种语言即快又安全,或者是否因对数组越界检查,安全包裹C语言库,或则其他一些类似东西而天生注定比C/C++慢两倍的问题仍然是开放的。

顺便问一下,究竟是什么使得Rust安全?简单的说,这门语言有内建的代码分析器,它是一个非常棘手的问题:它可以捕获所有典型的C++错误,不只是内存管理,而且同时考虑多线程等。通过一条管道来传递一个指定对象的引用到另外一个线程,然后试着自己使用这个引用 - 程序会拒绝通过编译。这确实非常酷。

但C++在过去30年一直屹立不倒,有足够的静态的和动态的分析器在这些时间段被发布出来。只是作为一个例子,看一个关于Google sanitizers(谷歌消毒剂)的一个短片 - 他们确实非常难。无论如何,在任何一个严肃的项目中,你使用一个连续集成的系统,运行一大堆的测试来编译生成。如果你不这么做的话,那么你的麻烦比语言缺乏安全性而言会更糟糕,因为静态的类型输入不会保证程序正确的按你的逻辑运行!所以,既然你总是运行测试,为什么不同时使用sanitizer?真的,他们没有找到所有的错误。

另一方面,如果你在你的代码的某个深处地方没有检查数组越界,并且Sanitizer也没有报告这个错误,也许,这仅仅由于所有必须的检查已经在上一层提供过了,同时,多一次检查不是会使程序变慢?即使没有sanitizers,你还可以发现许多东西供你在不同平台编译项目时提供伴随适当的失真的"assert(obj -> isValid)"风格论断来检查你代码的不变性。 粗糙的说,这个问题实际上涉及到过去那些好的老圣战,关于理论家(t)he(o)retic(异教徒)和集体农庄的软件开发方式(这是一个创新,但过于理想化的方法和一个传统实证方式,认为被前者的支持者粗心的简化了 - 原译者注)。

你经常可以听到一个论点,即90%的执行时间被10%的代码所执行(据我理解,这仅仅是一条经验主义 - 对一个主题快速的扫描互联网无法替代任何严格的科学的研究)。因此,你可以用安全的Rust语言写你大部分的代码,然后,剩下的10%(那些“热”代码)写在不安全的子集中,所以目前的Rust执行实际上不会有不好的性能。好的,但这不更是暗示我根本不需要Rust,因为我可以用Go写90%代码,然后用C写剩下的10%?只有那些寻找银弹的人和幻想神话的理论家(异教徒)会因为所有代码都100%用同一种语言编写而感到知足,而用Rust。但实际上一种语言有两种方言,这和"Java + C"或者"Go+C"组合没什么不同。

但实际上90/10规则是垃圾话。按照它的逻辑,我们可以用Java90%重写Webkit或者VirtualBox或者GCC而得到同样的结果。但这显然是错的。并不是这个比率因不同程序而变动太大,让我们做一些计算来瞧瞧。假设整个程序用不安全的C/C++编写,并且它的执行时间,假设是0.91(一小部分热代码)+0.11(一个冷代码的大部分)=1。现在和一个用一个带有C代码插入的安全语言编写的程序做比较: 0.91 + 0.12 = 1.1,这样,理论上说,区别是10%。是多了还是少了?这取决于项目的规模。以Google为例,即使是很少的一点比例就可以节省数百万美元(请看第五小结,“利用”,在这篇文章中)。或者想象下一个更新,JVM突然开始要求多10%的资源!我都害怕猜想需要多少个0在数字后面才能把比率转化为金钱。10%是C和C++完成任务所需要的所有份额。

我们不断的唱着“不成熟的优化是所有邪恶的根源”,就像一句咒语。但如果我们想要跟随它,为什么不在所有的代码里使用快速排序来替代冒泡排序?毕竟,我们没有办法确切的知道哪里是瓶颈,对吗?为什么要把普通的活动包含在actors或者事务内存中而不用马上使用更加高效的原子?并且,通常说,在小案例中,强制性的初始化每一个单独的变量,执行一堆辅助性的检查等等根本没有意义。让你仅花了额外的几分钟去思考而获取即使只有2~5%而不是10%的性能改进,其实也不坏。此外,就像我们已经指出的,这会使C/C++程序有巨大的差异!毕竟,谁敢争辩说找到一个热点,重写那些代码(也许有一堆)并且证明这真的变快了是一件比预先考虑性能而言更容易的工作?

即使除了速度/安全妥协的问题之外,我还怀疑这种语言设计。特别是关于使用的5种指针类型。一方面,让程序员仔细考虑他们的变量存放在栈或堆里,允不允许被多线程操作的想法并不坏。另一方面,想象你正在写一个程序,并在某一刻发现一些变量应该存在堆里而不是栈上。所以你用Box重写代码。接着你发现你实际上需要Rc或者Arc。再次,你重写了所有的代码。然后,再次,你重写它在栈上拥有普通变量。所有的东西你都手工操作而没有使用一个像样的IDE。正则表达式不会帮助。或者你刚刚结束了一个噩梦般的“Vec<Rc<RefCell<Box>>>” - 对Java说你好吧! 但可悲的事是编译器已经知道每一个变量的生存期,并会自动插入所有这些Box's,Arc's等等。但由于一些原因,这个责任被转移到程序员。它会让程序员更方便的写val(我们活在第三个千年,毕竟!)。在必要时,显式的指定特殊的Box或者Rc。从这一点看,Rust的开发已经搞砸了整件事情。

这个,特别的,让Rust's的使用范围变得更窄了。没有一个理智的人会用这样的一个语言写web或者服务器端软件 - 特别当考虑到它并没有提供比JVM相关语言更显著的优势。即使是Go - 带有普通轻量级的进程(没有前途) - 看起来都是一种更好的选择来解决这些任务。至于前途,你得学会如何正确的操作它们而不会砸到自己的脚 - 你说的是“安全语言”,啊?确实,所有的这些语言都有他们自己的特点 - 比如说“停止世界”的例子。但这个问题可以通过把代码分解成微服务或者通过其它技术而解决。并且是的,没有人愿意把Rust转为Javascript,通过它来为AWS写脚本或则为MongoDB来做查询脚本语言。至于安卓,这也是不可能的,但出于不同的原因:有一个以上的架构风格,那么JVM可以做的更好。因此,如果你恰巧认为Rust是“适合所有任务”的话,我让你失望了。

还有更多的理由来终结它:

宏使用拐杖来弥补正常的例外情况下所造成的过度的冗长。我已经写了关于元编程的问题 - 正是因为他们, 特别的, 导致我们没有办法得到一个像样的Rust IDE。 并且,即使我并不确定, 看起来Rust宏甚至并没有命名空间。

Cargo积极的鼓励绕过Crates.io从git中直接下载各种仓库就当人们是白痴。 作为一种结果,我们有被被巨量的混乱的包终结的风险,就像Erlang世界中的Rabar。顺便,我怀疑Go世界有同样的麻烦。

就像许多新语言,Rust正在走着简化的道路。我可以理解为什么它没有一个像样的继承和例外,但事实本身是有些人替我做让我觉得有些不舒服的决定。C++不会限制程序员说哪些他们可以或者不可以做。

现在,由于我们已经采取了简化的路径,为什么不扔掉所有的那些语言扩展?目前的事情的状况类似于Haskell的世界里,每个程序员都在用他们自己的方言在编码。

智能指针,让你知道,远远不会是免费的,不保证一个固定的垃圾收集时间。假如一些线程荣幸的释放一个非常深的数据结构会发生什么?当死引用在一个迷宫里徘徊时,所有依赖它的其他线程都安静的耐心的等待着。Erlang以及它的小块有同样的困难 - 我曾经自己面对过它许多次。智能指针自己本身也有一些问题 - 例如内存碎片化和泄漏。 就像在一个循环结构里只留下弱指针 - 整件事情搞砸了。所有这些都是一个语言试图假装变得安全点...如果你需要一个固定的GC时间,研究您的程序的行为,并采取预防措施(例如,提供对象池),如果你不满意这数字,或者可以手动管理内存。

有没有人看到Rust里面严格的语义描述吗?它至少有一个内存模型吗?当你考虑到它可以用10种方法解释源代码时,你还会称它为一个“安全”的语言,可以写出“确保正确”的程序?

我不得不再一次提醒你,麻烦的根源通常是人类,而不是科技。如果你的C++代码没有足够好,或者Java代码痛苦的运行缓慢,这不是由于这个技术是坏的 - 这是因为你还没有学会如何正确的使用它。 因此,你也不会因为一些其他原因而对Rust满意。学习那些更流行的工具并且喜欢上它不是更容易吗?

所以,我要总结一下,在未来五年里,我会投资我的时间去学习C/C++而不是Rust。C++是一个工业标准。过去30年来,程序员们一直用它去解决各种各样的任务。至于Rust和其他类似的 - 他们仅仅是奇怪的玩具带有模糊的未来。从2000年开始人们已经预测C++很快就会死亡,但自从那时开始起,C/C++并没有变得较少使用。事实恰恰相反,它是不断演进的(C++11, C++14),新工具的发布(举例说Clion和Clang),并且空间巨大。

一个C++程序员从来不会很难找到一个工资不错的工作,如果需要,可以很快的学会Rust。但相反的情况是非常,非常不可能发生。顺便说一下,找工作时,语言的选择从来都不是唯一的和最重要的事情。此外,一个熟练的C/C++程序员可以很容易地找到自己的方式在学习PostgreSQL's或者Linux核心代码,接触现代强大的开发工具,并且有一大堆的书和文章在手(比如说OpenGL)

所以,照顾一下您的健康吧,不要浪费你的时间 - 你只有比你想象的更少的时间!

You can’t perform that action at this time.