作为两门新语言,很多人可能将 Rust[1]和 Go[2] 视为相互竞争的编程语言,但 Rust 和 Go 团队并不这样认为。相反,两个团队非常尊重各自正在做的事情,并将这些语言视为对整个软件开发行业现代化的共同愿景的补充。本文的两位作者,一位是 Go 开发组成员,Hugo、Viper、Cobra 等优秀开源项目的作者;另一位是 Rust 开发组成员。

本文将讨论 Rust 和 Go 的优缺点以及它们如何相互补充和支持,同时给出什么场景最适合哪门语言的建议。

目前已经有一些公司发现同时使用这两种语言具有互补价值。为了让我们的想法更贴合用户体验,我们同三家这样的公司(Dropbox[3]、 Fastly[4] 和 Cloudflare[5] )探讨了关于 Rust 和 Go 一起使用方面的经验。在本文中将引用各个团队的观点。

1、Go 和 Rust 的比较

2、Go 和 Rust 的相似之处

Go 和 Rust 有很多共同点。他们都是现代编程语言,他们的诞生都是为了解决软件的安全性和可伸缩性。他们创建的目的都是为了解决当前行业中现有语言的缺陷,特别是开发者的生产率、软件的可伸缩性、安全性和并发性方面的不足。

当今流行的大多数语言都是在 30 多年前设计的。在设计这些语言时,与今天相比有五个主要区别:

  1. 摩尔定律被认为永远正确。
  2. 大多数软件项目是由小团队编写的,通常是一起工作。
  3. 大多数软件具有相对较少的依赖项,主要是专有的。
  4. 安全是次要的问题……或者根本不是问题。
  5. 软件通常是为单一平台编写的。

相比之下,Rust 和 Go 都是为当今世界编写的,并且通常采用类似的方法来设计一种满足当今开发需求的语言。

1)性能与并发

Go 和 Rust 都是专注于生成高效代码的编译语言。它们还提供对当今机器的多个处理器的轻松访问,使它们成为编写高效并发代码的理想语言。

以下是一些公司真实案例。

MercadoLibre 与 Go 一起成长[6]

使用 Go 之后,“MercadoLibre” 将原本服务器数量减少到原来的八分之一 (从 32 台服务器减少到 4 台),而且每个服务器可以使用更少的算力 (原来是 4 个 CPU 核,现在减少到 2 个 CPU 核)。使用 Go 之后,MercadoLibre 减少了 88% 的服务器费用,并将剩余服务器的 CPU 削减了一半, 节省了成本。

Bala Natarajan,Paypay[7]

在我们运行 Go 代码的严格管理的环境中,我们看到 CPU 减少了大约 10% [vs C++],代码更清晰、可维护。

Matt Asay,亚马逊网络服务[8]

在 AWS,我们也喜欢 Rust,因为它可以帮助 AWS 编写高性能、安全的基础设施级网络和其他系统软件。亚马逊第一个使用 Rust 构建的著名产品 Firecracker 于 2018 年公开推出,提供支持 AWS Lambda 和其他无服务器产品的开源虚拟化技术。但我们也使用 Rust 来提供服务,例如 Amazon Simple Storage Service (Amazon S3)、Amazon Elastic Compute Cloud (Amazon EC2)、Amazon CloudFront、Amazon Route 53 等。最近,我们推出了 Bottlerocket,这是一个用 Rust 编写的基于 Linux 的容器操作系统。

Josh Hannaford, IBM[9]

我们看到速度惊人地增长了 1200-1500%! 我们从用 scala 实现的产品化更多的时间做更少的事情 (300-500ms),到 Rust 实现的产品花费更少的时间做更多的事情 (25-30ms)

2)团队可扩展——可审查

当今软件的开发团队可能是不断变化的 (团队成员可能是不断扩充),一般是以分布式的方式进行代码管理。Go 和 Rust 都是为团队的工作方式而设计的,通过消除不必要的问题,如格式、安全性和复杂的组织,来改善代码审查。这两种语言都需要相对较少的上下文来理解代码正在做什么,从而允许审查人员更快地处理其他人编写的代码,包括团队成员的代码和外部的开源代码。

业界的一些看法。

Sam Rose, CV 合作伙伴[10]

因为我早期的职业生涯主要是 Java 和 Ruby,构建感觉就像是我肩上不可能的重担。当我在 Google 时,遇到一个用 Go 编写的服务让我松了一口气,我发现它很容易构建和运行。Rust 也是如此,尽管我只在小得多的规模上进行了研究。我希望无限可配置的构建系统的时代已经过去,所有语言都带有自己的专用构建工具,开箱即用。

Daniel Reiter Horn, Dropbox:

在用 Go 编写服务时,我松了一口气,因为与动态语言相比,它有一个非常简单、易于推断的静态类型系统,并发性是一等公民,而且 Go 的标准库令人难以置信优美而有力,但也恰到好处。进行标准的 Go 安装,加入 grpc 库和数据库连接器,你几乎不需要其他任何东西就可以在服务器端构建任何东西,并且每个工程师都能够阅读代码并理解库。在用 Rust 编写模块时,Dropbox 工程师在 Async-await 于 2019 年稳定之前就感受到了 Rust 在服务器端的成长痛苦,但从那时起,crates 开始融合使用它,我们获得了异步模式和无畏并发的好处。

3)开源意识

今天普通软件项目使用的依赖项数量是惊人的。数十年来软件重用的目标已经在现代开发中实现,今天的软件是使用数百个项目构建的。为此,开发人员使用软件存储库,它日益成为各种应用程序中软件开发的主要内容。开发人员包含的每个包都有自己的依赖项。当今编程环境的语言需要毫不费力地处理这种复杂性。

Go 和 Rust 都有包管理系统,允许开发人员制作他们想要构建的包的简单列表,语言工具会自动为他们获取和维护这些包,以便开发人员可以更专注于自己的工作代码,少管别人。

4)安全性

Go 和 Rust 都很好地解决了当今应用程序的安全问题,确保在这些语言中构建的代码运行时不会将用户暴露于各种经典的安全漏洞,如缓冲区溢出、释放后使用等。没有这些顾虑,开发人员就可以专注于手头的问题,并构建默认情况下更安全的应用程序。

业界对此的一些观点。

Josh Hannaford, IBM[11]

在处理你遇到的错误时,Rust 编译器会帮助你解决问题。这让你可以专注于你的业务目标,而不是寻找错误或破译神秘的消息。译注:和编译器作斗争。哈哈哈~

Taylor Thomas, Sr., Microsoft[12]

简而言之,Rust 的灵活性、安全性超过了必须严格遵循的生命周期、借用和其他编译器规则甚至缺少垃圾收集器的任何不便。这些功能是云软件项目急需的补充,将有助于避免其中常见的许多错误。

Stefan Nilsson,计算机科学教授[13]

Go 是静态强类型,没有隐式转换,但语法开销仍然非常小。这是通过赋值中的简单类型推断以及无类型数字常量来实现的。这为 Go 提供了比 Java(具有隐式转换)更强的类型安全性,但代码读起来更像 Python(具有无类型变量)。

Daniel Reiter Horn,Dropbox:

在构建用于在 Dropbox 存储块数据的 Brotli 压缩库时,我们将自己限制在 Rust 的安全子集,此外,还限制了核心库(no-stdlib),并将分配器指定为泛型。以这种方式使用 Rust 的子集使得在客户端从 Rust 调用 Rust-Brotli 库并在服务器上使用来自 Python 和 Go 的 C FFI 变得非常容易。这种编译模式也提供了实质性的安全保证[14]。经过一些调整后,尽管 100% 安全、经过数组边界检查的代码,Rust Brotli 实现仍然比 C 中相应的本机 Brotli 代码快。

5)真正便携

在 Go 和 Rust 中编写一个可以在许多不同操作系统和架构上运行的软件都是微不足道的。“一次编写,随处编译”。此外,Go 和 Rust 本身都支持交叉编译,消除了通常与旧编译语言相关的“构建农场”的需要。

对此,业界的看法。

Dewet Diener, Curve[15]

Golang 具有生产优化的优良品质,例如内存占用小,这支持其在大型项目中构建块的能力,以及开箱即用的轻松交叉编译到其他架构的能力。由于 Go 代码被编译成单个静态二进制文件,因此可以轻松进行容器化,并且通过扩展,将 Go 部署到任何高度可用的环境(例如 Kubernetes)中几乎是小菜一碟。

Brian Ketelsen, Microsoft[16]

当你查看基于云的基础设施时,你通常会使用 Docker 容器之类的东西来部署你的工作负载。使用你在 Go 中构建的静态二进制文件,你可以拥有一个 10、11、12 兆字节的 Docker 文件,而不是引入整个 Node.js 生态系统、Python 或 Java,在那里你有数百兆字节大小的 Docker 文件。所以,传输那个微小的二进制文件真是太棒了。

Matt Ronge, Astropad[17]

有了 Rust,我们将拥有一个高性能和便携的平台,我们可以轻松地在 Mac、iOS、Linux、Android 和 Windows 上运行。

3、Go 和 Rust 的不同之处

在设计中,总是需要权衡取舍。虽然 Go 和 Rust 大约在同一时间出现,有着相似的目标,但有时由于面临决策,他们选择了不同的权衡,这些权衡在关键方面将语言区分开。

1)性能

Go 具有开箱即用的出色性能。按照设计,没有任何旋钮或控制杆(译注:即所谓的调优)可让你从 Go 中获得更多性能。Rust 旨在使你能够从代码中挤出每一滴性能;在这方面,你今天真的找不到比 Rust 更快的语言。然而,Rust 的性能提升是以增加复杂性为代价的。

业界对此又是什么看法?

Jesse Howarth, Discord[18]

值得注意的是,在编写 Rust 版本时,我们只对优化进行了非常基本的考虑。即使只是基本优化,Rust 也能够胜过超手动调整的 Go 版本。这极大地证明了与我们必须使用 Go 进行的深入研究相比,使用 Rust 编写高效的程序是多么容易。

Daniel Reiter Horn,Dropbox:

通过将逐行 Python 代码移植到 Go 中,Dropbox 工程师经常看到 5 倍的性能和延迟改进,与 Python 相比,内存使用量通常会大幅下降,因为没有 GIL,并且进程数可能会减少。但是,当我们受到内存限制时,例如在桌面客户端软件或某些服务器进程中,我们会转向 Rust,因为 Rust 中的手动内存管理比 Go GC 效率高得多。

2)适应性/交互性

Go 的快速迭代优势允许开发人员快速尝试想法和手头任务的工作代码。通常,这就足够了,并且可以让开发人员腾出时间处理其他任务。另一方面,与 Go 相比,Rust 的编译时间更长,导致迭代时间更慢。这导致 Go 在更快的周转时间允许开发人员适应不断变化的需求的场景中工作得更好,而 Rust 在可以有更多时间进行更精细和高性能的实现的场景中蓬勃发展。

Daniel Reiter Horn, Dropbox:

Go 类型系统的天才之处在于调用者可以定义接口,允许库返回扩展结构但需要窄接口。Rust 类型系统的天才之处在于匹配语法与 Result<> 的组合,在这种情况下,你可以静态地确定每个可能性都得到了处理,而不必发明空值来满足未使用的返回参数。

Peter Bourgon, Fastly:

如果你的用例更接近客户,它更容易受到需求变化的影响,那么 Go 会更好,因为持续重构的成本要便宜得多。关键是你能以多快的速度表达新的需求并进行尝试。

3)可学习性

简而言之,真的没有比 Go 更平易近人的语言了。有许多团队能够在几周内采用 Go 并将 Go 服务/应用程序投入生产的故事。此外,Go 在语言中相对独特,因为它的语言设计和实践在其 10 多年的生命周期中非常一致。所以花在学习 Go 上的时间会在很长一段时间内保持其价值。相比之下,由于其复杂性,Rust 被认为是一种难以学习的语言。通常需要几个月的时间学习 Rust 才能适应它,但这种额外的复杂性带来了精确的控制和性能的提高。

对此大家怎么看的?

Jaime Garcia, Capital One[19]

当时,没有一个团队成员知道 Go,但在一个月内,每个人都在用 Go 工作。

American Express Uses Go for Payments & Rewards[20]

Go 与其他编程语言的不同之处在于认知负荷。你可以用更少的代码做更多的事情,这使得你更容易推理和理解你最终编写的代码。大多数 Go 代码最终看起来非常相似,因此,即使你正在使用全新的代码库,你也可以快速启动并运行。

Dewet Diener, Curve[21]

然而,与其他编程语言不同,Go 的创建是为了最大限度地提高用户效率。因此,具有 Java 或 PHP 背景的开发人员和工程师可以在几周内获得使用 Go 的技能和能力——根据我们的经验,他们中的许多人最终更喜欢它。

4)精准控制

也许 Rust 的最大优势之一是开发人员对如何管理内存、如何使用机器的可用资源、如何优化代码以及如何制定问题解决方案的控制量。与 Go 相比,这并非没有很大的复杂性成本,Go 的设计较少用于这种类型的精确制作,而更多的是为了更快的探索时间和更快的周转时间。

John Graham-Cumming,Cloudflare:

随着我们对 Rust 的经验的增长,它在另外两个方面显示出优势:作为一种具有强大内存安全性的语言,它是边缘处理的不错选择,作为一种具有极大热情的语言,它成为一种从头开始流行的语言组件。

4、总结/关键要点

Go 的简单性、性能和开发者的生产力使它成为创建面向用户的应用程序和服务的理想语言。快速迭代允许团队快速调整以满足用户不断变化的需求,为团队提供一种将精力集中在灵活性上的方式。

Rust 的更精细的控制允许更精确的操作,这使得 Rust 成为低级别操作的理想语言,这些操作不太可能发生变化,而且与 Go 相比,它的性能略有改善,尤其是在大规模部署的情况下。

Rust 的优势是最接近机器。Go 的优势们更接近的用户。这并不是说要么不能在另一个空间中工作,但它会增加难度。随着您的需求从灵活性转变为效率,用 Rust 重写库是非常有利的。

虽然 Go 和 Rust 的设计有很大的不同,但它们的设计发挥了一套兼容的优势,当它们一起使用时,可以实现很大的灵活性和性能。

5、建议

对于大多数公司和用户来说,Go 是正确的默认选项。它的性能强大,Go 很容易使用,并且 Go 的高度模块化特性使它特别适合需求变化或演进的情况。

随着产品的成熟和需求的稳定,可能会有机会从性能的微小增长中获得巨大的收益。在这些情况下,使用 Rust 来最大化性能可能更值得。

原文链接:/rust-vs-go-why-theyre-better-together/


所以,Go 爱好者可以学学 Rust;Rust 爱好者也可以学学 Go。

参考资料

[1]

Rust: /

[2]

Go: v/

[3]

Dropbox: /

[4]

Fastly: /

[5]

Cloudflare: /

[6]

MercadoLibre 与 Go 一起成长: v/solutions/mercadolibre/

[7]

Bala Natarajan,Paypay: v/solutions/paypal/

[8]

Matt Asay,亚马逊网络服务: https://aws.amazon.com/blogs/opensource/why-aws-loves-rust-and-how-wed-like-to-help/

[9]

Josh Hannaford, IBM: https://developer.ibm.com/technologies/web-development/articles/why-webassembly-and-rust-together-improve-nodejs-performance/

[10]

Sam Rose, CV 合作伙伴: /golang/rust-vs-go

[11]

Josh Hannaford, IBM: https://developer.ibm.com/technologies/web-development/articles/why-webassembly-and-rust-together-improve-nodejs-performance/

[12]

Taylor Thomas, Sr., Microsoft: https://msrc-blog.microsoft.com/2020/04/29/the-safety-boat-kubernetes-and-rust/

[13]

Stefan Nilsson,计算机科学教授: /golang/advantages-over-java-python/

[14]

实质性的安全保证: /infrastructure/lossless-compression-with-brotli

[15]

Dewet Diener, Curve: /golang-curve-163187.html

[16]

Brian Ketelsen, Microsoft: https://cloudblogs.microsoft.com/opensource/2018/02/21/go-lang-brian-ketelsen-explains-fast-growth/

[17]

Matt Ronge, Astropad: /why-rust/

[18]

Jesse Howarth, Discord: /why-discord-is-switching-from-go-to-rust-a190bbca2b1f

[19]

Jaime Garcia, Capital One: /capital-one-tech/a-serverless-and-go-journey-credit-offers-api-74ef1f9fde7f

[20]

American Express Uses Go for Payments & Rewards: v/solutions/americanexpress/

[21]

Dewet Diener, Curve: /golang-curve-163187.html