阿里、蚂蚁、晟腾、中科加禾精彩分享 AI 基础设施洞见,现购票可享受 9 折优惠 |AICon 了解详情
写点什么

为什么是 Go 而不是 Rust

  • 2019-09-19
  • 本文字数:4325 字

    阅读完需:约 14 分钟

为什么是Go而不是Rust

本文最初发布于 Loris Cro 的个人博客,经原作者 Loris Cro 授权由 InfoQ 中文站翻译并分享。


导读: Go 和 Rust 都是时下非常火爆的语言,这两者孰优孰劣,在网上就形成了两大阵营,互不相让。小编翻译本文后不久就赫然发现一篇与本文“正面刚”的文章:Why Rust and not Go ,小编大致看了一下,这两篇文章互相批驳彼此,有兴趣的读者看完本文后,不妨也看看那篇反驳的文章。


在 Rust 的宇宙中,Go 扮演的角色是什么?


假设你是一名主要用 Go 语言的开发者。你去参加一次活动,在和一些人聊天的时候,你决定告诉他们,你为了做某事而编写了一个小工具。你声称,这个小工具是用 Go 语言编写的,因此速度相当快,它是一个二进制文件,等等。大家似乎对你的叙述感到很满意,你开始自我感觉良好,但随后,你注意到,有一个陌生人从后面走过来,一个声音传来,句句渗透着道道寒意:“你为什么用 Go 而不用 Rust 呢?”


你开始感到有些局促不安。好吧,你可以回答你只知道 Go 语言,所以就用 Go 来解决问题,但这可能不会是一个令人满意的答案。你在一开始就自豪地炫耀你的工具跑得有多快,但很显然,陌生人会用 Rust 给 Go 带来的好处来反驳你过于简单化的借口。


我开始感到很沮丧。当初你为什么会选择学习 Go 语言?有人告诉你,Go 的速度很快,而且它有很好的并发原语。现在,Rust 横空出世,每个人都在说,Rust 在各个方面都更好。他们是以前就说谎了呢,还是现在就在说谎呢?虽然没有单一的语言能够统治所有的语言,但你知道,人们仍然有可能做出错误的选择,最终陷入技术死胡同。毕竟,几年前你确实在其他语言中,选择了 Go 语言,你很高兴地加入圈子并融入其中,还问“为什么不用 Go 呢?”


虽然上面的故事完全是我虚构出来的,但毫无疑问的是,Rust 有一些拥趸,他们过于激进,觉得有义务向每一个迷失的灵魂灌输螃蟹大神的美德。(译注:Rust 语言的吉祥物就是一只螃蟹 Ferris,这是因为 Rust 开发者有一个名字,叫 Rustacean,因为这个是从甲壳纲动物这个单词 Crustacean [krʌ’steʃən],去掉了首字母 C,而演变而来的。因为这里面包含 Rust 这四个字母。)这真的并不是 Rust 的错,每个成功的项目都会有行为不端的追随者,这是很难避免的。虽然每个人都必须与这些人打交道,但我觉得,Go 开发者特别容易受到他们行为的影响,因为 Rust 和 Go 的消息传递有太多的重叠。


Go 速度很快,但 Rust 速度更快。


Go 有一个高效的垃圾收集器,但 Rust 有静态内存管理。


Go 有很好的并发支持,但 Rust 有可证明的正确并发性。


Go 有接口,但 Rust 有特性和其他零成本的抽象。


如果你是一名 Go 开发者,你可能会有点上当受骗的感觉。相比之下,Python 开发者就不怎么特别担心 Rust。他们知道,Python 在很多方面,速度慢,效率低,但他们对此并不介意,因为他们知晓 Python 的角色:使代码易于编写,并在当性能很重要时,将其转到 C 语言来开发。


Go 语言怎么样呢?

Go 非常适合用来编写服务

Google 创建 Go 语言是为了解决 Google 的问题,这些问题主要涉及网络服务。Go 的并发模型非常适合服务器端应用程序,这些应用程序必须主要处理多个独立请求,而不是参与复杂的结果传递方案。这就是为什么给你的是 go 而不是 wait 的原因之一。


Go 对 HTTP 和相关协议有很好的支持,并且,编写一个令人满意的 Web 服务并不需要很长的时间。在我的个人项目中,Go 被证明是 Node.js 的很好替代方案,尤其是在我想要比编写惯用的 JavaScript 更明确地确定不同组件之间的接口的情况下。


除此之外,它还有强大的工具,可用来诊断并发性和性能问题,而且交叉编译使得 Go 在任何平台上部署都变得轻而易举。

Go 无可置辩地简单

Go 以提供了一组有限的内置语言功能而感到自豪。这使得 Go 易于学习,更重要的是,它确保了 Go 项目即使在规模不断扩大的情况下,代码仍然可以理解。Go 的创造者喜欢称之为一种“无聊”的语言。虽然我们可以争论这种语言是否可以使用一种或两种额外的东西,但事实证明,迫使人们“少花钱多办事”的想法是非常成功的。


在 Web 服务方面,Rust 确实可以做到和 Go 一样好,甚至更好,但就简单性方面而言,它确实不能与 Go 相比。而且 Go 不只是简单,它对其他语言通常比较宽松的东西也很严格。Go 不希望在同一个目录中有未使用的变量或导入、属于不同包的文件等等。它甚至曾经抱怨在 GOPATH 之外保存的项目(谢天谢地,现在不再是这样了)。


Go 也不希望在代码中留有任何“指纹”,因此它通过 go fmt 强制转换成单一的、通用的代码风格。


事实上,这些事情没有一件特别令人印象深刻,但它们确实描述了 Go 语言想要强加于人的心态。因此许多人不喜欢它。但在我看来,它是某些开发类型(如企业软件)的杀手级特性。

Go 对企业软件来说非常棒

正如我已经提到的,Go 的创建,是为了解决 Google 的问题,而 Google 的问题绝对是企业级的问题。无论这是创造者的直接目的,还是在大公司使用它的自然结果,Go 宛如一股清流,无疑为企业软件开发带来了令人兴叹的新鲜空气。


如果你有编写企业软件的经验,并且尝试过 Go 语言,那你可能会明白我的意思。下面是简短的总结。


与其他类型的开发相比,企业开发是一个非常怪异的“野兽”。如果你从来没有这样做过,你可能会扪心自问:“到底什么是企业软件?”我曾经做过一段时间的开发顾问,下面是我对这一问题的看法。

企业软件开发与规模有关

企业软件并不以用户总数或数据量为依据。通常情况亦如此,但定义性特征是范围过程的规模。


企业软件总是有很大的范围。 这个领域可以大而宽,也可以是窄而复杂,有时二者兼而有之。当创建软件来为这样的领域进行建模时,由于非技术方面的关注超过了大多数技术方面的考虑,造成正常的编程智慧极其短缺。


要解开这一复杂的领域,你需要一个结构良好的过程。 你需要领域专家、分析师和一种机制,让利益相关者评估正在进行的流程。这也是经常发生的情况,作为技术专家,你并不十分了解这个领域。利益相关者和领域专家通常也不太了解技术。


这进一步降低了诸如效率、甚至正确性等技术问题。不要误会我的意思,企业确实很关心正确性,但他们对正确性有不同的定义。当你考虑算法的正确性时,而他们考虑的却是在劳动力廉价的国家为他们的运营团队建立一个协调的后勤办公室。


由于这个大前提所带来的环境,随着时间的推移,出现了一些著名的企业开发“怪癖”。我将举出三个与我的观点相关的例子。


  1. 有很多初级开发者在工作中学习如何编程,但大多数人并没有幸运地找到一份能够真正教会他们任何东西的工作。在一些地方,当你被聘用后,就会被安排在 PluralSight 进行为期一周的培训,然后你就被认为已经为上岗做好了准备。

  2. 出于各种错误的原因,软件项目很快变得庞大而复杂。 大型项目需要时间来构建,而人员(或整个团队)会在此期间流动。Constant 重构从来都不是一种选择,因此每个重构都会留下大量代码,这些代码的质量参差不齐。多个团队并行工作也会产生冗余代码。领域会随着时间的推移而发生变化,不可避免地使旧的假设失效,从而引起抽象泄漏。抽象越复杂,当业务返回严重的变更请求时,它成为问题的风险就越大。

  3. 工具链通常很槽糕,而且经常过时。 到目前为止,这几乎是我所描述的一切的必然结果。大量的旧代码会将你束缚在特定的工具集上,初级开发者充其量只能了解现状,而高层(管理者和利益相关者)往往根本就没有准备好根据第一手经验做出技术决策,这种努力的一般性质使他们厌恶风险,导致他们主要以模仿自己所在领域的其他成功玩家所做的事情为主,或者更确切地说,分析师声称,其他成功的玩家都是这样做的。

Go 就是要在规模上抑制复杂性

Go 让团队更成功,部分原因是基于他们比其他生态系统更多的东西,部分原因是拿走他们的工具,来防止掉进常见的陷阱。


Go 比 Java 或 C 语言更容易学习。加快速度通常是好事儿,但当项目落后、截止日期临近时,管理层必然诉诸于雇佣更多的人,希望(徒劳地)加快项目进度时,加快速度就变得至关重要了。


Go 社区将 Java/C 等经常使用的许多抽象视为反模式,例如 IoC 容器,或 OOP 继承等等。只有两个级别的可见性变量,而且唯一的并发模型是 CSP。使用 Go 进行编程,与 Java/C 相比,Go 更难陷入难以理解的陷阱。


Go 编译器速度很快。 这意味着,在通常情况下,运行测试会更快,部署会话费更少的时间,从而提高了整体生产率。


使用 Go,初级开发者更容易提高工作效率;而作为中级开发者,更难引入脆弱的抽象概念,这些抽象会导致出现问题。


处于这些原因,对于企业软件开发来说,Rust 不如 Go 那般有吸引力。但这并不意味着 Go 就是完美的,也并不意味着 Rust 比 Go 更有优势。相比 Go,Rust 固然有很多优点,但最重要的是,我认为,人们对 Go 的普遍看法是错的。


Go 谈不上极快,而且内存利用效率也不是超强。Go 也没有绝对最好的并发模型。


Go 比 Java/C# 更快、更有内存效率,并且绝对比 Java/C# 有更好的并发性。Go 很简单,所以,当面对普通的 Go 程序与普通的 Java/C# 程序时,所有这一切都可以成立。 从绝对意义上来说,GO 是否真的比 C# 或 Java 快,这并不重要。普通的 Java/C# 程序户与最好的理论程序大相径庭,并且与 Go 相比,这些语言中的危险东西太多了。如果你想要一个例子,看看这篇 Brandon Minnick 的关于 C# 并发性的演讲《纠正 .NET 常见的异步 / 等待错误》(Correcting Common Async/Await Mistakes in .NET),在我看来,这是难以置信的,因为直接使用 await ,从来都不是正确的做法。试想一下,普通的异步 C# 应用程序有多糟糕。事实上,ASP.NET 应用程序出现死锁时,却没有明显的原因,这样的情况并不少见。



它会发生死锁吗?


上面图片取自这篇博文:《理解异步,避免 C#中的死锁》(Understanding Async, Avoiding Deadlocks in C#),该文试图解释了 C# 中分解并发的无数种方式。

结论

Go 是一个更好的 Java/C#,而 Rust 则不是。Go 可以给企业软件开发带来清晰度,这无疑比降低整体生产率为代价的清除垃圾收集更有价值。


Rust 是一个更好的 C++,即使你偶尔听到有人说 Go 是一个更好的 C,但事实并非如此。任何带有内置垃圾收集器和运行时的语言,都不能被视为 C 语言。别搞错了,Rust 才是 C++,而不是 C。如果你想要更好的 C,请看看 Zig。


最后,回到正题,并不是所有的“为什么不是 Rust”的问题都应该如上面的例子那样解释。有时候你会感到阵阵寒意,那些问你这个可怕问题的人,只想知道你的想法。我们要做的是避免将自己的身份与单一的语言捆绑在一起,首先要拥抱实用性。像 Rustacean 或 Gopher 这样的部落名字应该避免,因为它们本质上就是一种营销工具,用来诱导更强的品牌效应。


作者介绍:


Loris Cro 是供职于 Redis Lab 的开发者,爱好编程和设计原则。


原文链接:


Why Go and not Rust?


2019-09-19 18:056508
用户头像

发布了 368 篇内容, 共 170.2 次阅读, 收获喜欢 939 次。

关注

评论 2 条评论

发布
用户头像
if err != nil
2019-09-20 14:21
回复
return err
2019-09-21 17:33
回复
没有更多了
发现更多内容

华为数通HCIA小型拓扑综合实验,运用OSPF动态路由协议、ACL访问控制列表,交换机生成树协议,修改交换机根桥、交换机划分vlan、链路聚合等相关数通技术、NAT地址转换以及NAT网络地址转换的配置

Python-派大星

10月月更

NAT基础:NAT技术原理,静态NAT、动态NAT、NAPT、Easy IP、NAT Server的原理,以及各NAT的配置方法和转换示例。

Python-派大星

10月月更

【一Go到底】第二十八天---数组实际案例与复杂应用

指剑

Go golang 10月月更

JUC面试题

Andy

立即可用的实战源码(springboot+redis+mybatis+restTemplate)

程序员欣宸

Java springboot 10月月更

如何在C#或VB.NET程序中为幻灯片添加或删除批注

Geek_249eec

C# PPT VB.NET

专访韩向东|元年科技:专业与技术并重,赋能财务数字化转型

元年技术洞察

数字化转型 财务数字化

36氪|元年科技发布新版数字化PaaS平台,更新多个组件

元年技术洞察

方舟 PaaS 中台战略 企业数字化

鸿蒙开发实例 | 鸿蒙操作系统的前世今生

TiAmo

华为 鸿蒙 10月月更

AR人体姿态识别,实现无边界的人机交互

HMS Core

AR

极客时间运维进阶训练营第二周作业

忙着长大#

极客时间

vue3 name 属性的使用技巧

new_cheng

Vue 前端 Vue3 VUE 3.0 源码

京东云开发者|京东云RDS数据迁移常见场景攻略

京东科技开发者

MySQL 数据同步 数据迁移 云迁移 数据订阅

JUC 浅析(二)

Andy

极客时间运维进阶训练营第二周作业

9527

Spark On Kubernetes 的 Web UI 访问实践

移动云大数据

Spark on k8s在阿里云EMR的优化实践

阿里云大数据AI技术

大数据 spark 企业号十月PK榜

FlyFish一周年,社区大咖邀你共话开源!

云智慧AIOps社区

低代码 可视化 数据可视化 大屏可视化 无代码

从“汽车制造”生活案例到软件的建造者模式

宇宙之一粟

设计模式 建造者模式 Go 语言 10月月更

订单中心架构设计与实践

小小怪下士

Java 程序员 系统架构 架构设计

数字化时代,企业如何创新自己的客户服务

Baklib

“程”风破浪的开发者|学习中的境界

林冲

学习方法 “程”风破浪的开发者

对话创始人:团队研发效能应该如何管理和度量?

LigaAI

团队管理 敏捷开发 研发管理 研发效能 企业号十月PK榜

推广TrustAI可信分析:通过提升数据质量来增强在ERNIE模型下性能

汀丶人工智能

nlp

2022最新CSS高频面试题指南

CoderBin

CSS 前端 面试题 秋招 10月月更

JUC浅析(一)

Andy

String源码分析(二)

知识浅谈

String类 10月月更

要努力,但也别焦虑

源字节1号

程序人生

27位技术实战派负责人齐聚 深聊降本增效 你一定不想错过!

阿里技术

云计算 云原生 云栖大会 降本增效

阿里云云边一体容器架构创新论文被云计算顶会 ACM SoCC 录用

阿里巴巴云原生

阿里云 云原生 容器服务

ACL访问控制列表 基础、创建ACL访问控制列表的两种方式、配置ACL访问控制列表规则、修改ACL规则的默认步长。子网掩码、反掩码、通配符掩码的区别和作用。

Python-派大星

10月月更

为什么是Go而不是Rust_开源_Loris Cro_InfoQ精选文章