Rust 和 Go 该如何选择?

共 884字,需浏览 2分钟

 ·

2021-10-11 16:17

何时使用Rust和何时使用Golang

随着 Rust 的发展和一些 Gopher 关注 Rust,有人提出疑问:Rust 会侵蚀 Go 的市场?本文就一起看看,什么时候适合使用 Go,什么时候适合使用 Rust?


一开始,Go 和 Rust 之间就有明显的区别。Go 更加专注于构建可扩展的 Web API 和微服务,尤其是借助 Goroutines 的强大功能。后者对于 Rust 也是可能的,但是从开发人员的体验来看,事情会相对比较难做。

Rust 非常适合处理大量数据和其他 CPU 密集型操作,例如执行算法。这是 Rust 相比 Go 的最大优势。要求高性能的项目通常更适合 Rust。

在本教程中,我们将对 Golang 和 Rust 进行比较,评估这两门编程语言的性能,并发性,内存管理和整体开发人员体验。我们还将概述这些元素,以帮助您一目了然地为项目选择正确的语言。

如果你刚开始使用 Rust,那么在继续阅读之前,最好先阅读一下该初学者指南[1]

01 性能

Go 最初是由 Google 的工程师设计的,于 2009 年向公众推出。它的创建是为了提供 C++ 的替代方案,该替代方案易于学习和编码,并且经过优化可在多核 CPU 上运行。

从那时起,Go 对于希望利用该语言提供的并发性的开发人员来说非常有用。该语言提供了 goroutine,使你可以将函数作为子流程运行。

Go 的一大优势是你可以轻松使用 goroutines。只需将 go 语法添加到函数即可使其作为子流程(subprocess)运行。Go 的并发模型允许你跨多个 CPU 内核部署工作负载,从而使其成为一种非常有效的语言。

package main

import (
    "fmt"
    "time"
)

func f(from string) {
    for i := 0; i < 3; i++ {
        fmt.Println(from, ":", i)
    }
}

func main() {
    f("direct")

    go f("goroutine")
    time.Sleep(time.Second)
    fmt.Println("done")
}

尽管有多核 CPU 支持,Rust 仍然设法超越 Go。Rust 在执行算法和资源密集型操作方面效率更高。该基准测试[2]比较了 rust 和 golang 的不同算法,如二叉树。对于所有经过测试的算法,Rust 至少快 30%;在二叉树计算的情况下,最高可达 1,000%。Bitbucket[3] 的一项研究表明,Rust 与 C++的性能相似。

根据Bitbucket的防锈性能

(来源:bechmarksgame[4]

02 并发

如上所述,Go 支持并发。例如,假设你正在运行一个处理 API 请求的 Web 服务器。你可以使用 Go 的 goroutine 程序将每个请求作为 subprocess 运行,通过将任务分发到所有可用的 CPU 内核来最大程度地提高效率。

Goroutines 是 Go 内置函数的一部分,而 Rust 仅接收本机 sync/wait 语法来支持并发。因此,在并发方面,Golang 的开发人员有体验优势。但是,Rust 在保证内存安全方面要好得多。

这是 Rust 的简化线程的示例:

use std::thread;
use std::time::Duration;

fn main() {
   // 1. create a new thread
   for i in 1..10 {
      thread::spawn(|| {
         println!("thread: number {}!", i);
         thread::sleep(Duration::from_millis(100));
      });
   }

  println!("hi from the main thread!");
}

并发一直是开发人员的棘手问题。在不影响开发人员体验的情况下保证内存安全的并发性并不是一项容易的任务。但是,这种极端安全的关注导致创建了可证明正确的并发[5]。Rust 尝试使用所有权概念来防止未经请求的资源访问,以防止出现内存安全错误。

Rust 提供了四种不同的并发范例,以帮助你避免常见的内存安全陷阱。我们将仔细研究两个常见的范例:channel 和锁。

channel(通道)

通道[6]有助于从一个线程传送消息到另一个。虽然 Golang 也有此概念,但 Rust 允许你将指针[7]从一个线程转移到另一个线程,以避免争用资源。通过传递指针,Rust 可以对通道强制执行线程隔离。再一次,Rust 在并发模型方面表现出对内存安全的痴迷。

仅当持有[8]时才能访问数据。Rust 依赖于锁定数据而不是 cod 的原理,而 cod 经常可在诸如 Java 之类的编程语言中找到。

有关所有权和所有并发范例的更多详细信息,请查看“使用 Rust 进行无所畏惧的并发[9]”。

03 内存安全

所有权概念是 Rust 的主要卖点之一。Rust 将类型安全[10]提升到了新的水平,这对于实现内存安全的并发性也很重要。

根据 Bitbucket 博客[11],“ Rust 非常严格和繁琐的编译器会检查你使用的每个变量以及你引用的每个内存地址。它避免了可能发生的数据争用情况,并告知你未定义的行为。”

这意味着由于 Rust 对内存安全性的极度痴迷,你最终不会出现缓冲区溢出或争用情况。但是,这也有其缺点。例如,你在编写代码时必须非常了解内存分配原则。始终保持内存安全防护并不容易。

04 开发人员体验

首先,让我们看一下这两门语言的学习曲线。Go 在设计时考虑了简单性。开发人员经常将其称为“无聊”语言,也就是说,其有限的内置功能集使 Go 易于使用。

此外,Go 提供了 C++ 的更简单替代方案,隐藏了诸如内存安全性和内存分配等功能。Rust 采用了另一种方法,迫使您考虑诸如内存安全性的概念。所有权的概念和传递指针的能力使 Rust 失去了学习的吸引力。当你不断考虑内存安全性时,你的工作效率就会降低,并且你的代码注定会变得更加复杂。

与 Go 相比,Rust 的学习曲线非常陡峭。值得一提的是,与 Python 和 JavaScript 等动态语言相比,Go 的学习曲线会陡峭些。

05 何时使用 Go

Go 在各种场景中都能很好地工作,使其成为 Web API 的很好选择。正如Loris Cro[12]指出的那样,“ Go 的并发模型非常适合必须处理多个独立请求的服务器端应用程序”。这正是 Go 提供 goroutines 的原因。

此外,Go 内置了对 HTTP Web 协议的支持。你可以使用内置的 HTTP 支持快速设计一个小型 API,并将其作为微服务运行。因此,Go 非常适合微服务架构并满足 API 开发人员的需求。

简而言之,如果你重视开发速度并且更喜欢语法简单而不是性能,那么 Go 是一个很好的选择。最重要的是,Go 提供了更好的代码可读性,这对于大型开发团队而言是一个重要标准。

在以下情况下选择 Go:

  • 你关心简单性和可读性
  • 你需要一种简单的语法来快速编写代码
  • 你想使用支持 Web 开发的更灵活的语言

06 何时使用 Rust

当性能很重要时,例如在处理大量数据时,Rust 是一个不错的选择。此外,Rust 为你提供了对线程行为以及线程之间资源共享方式的细粒度控制。

另一方面,Rust 学习曲线陡峭,并且由于内存安全性的额外复杂性而减慢了开发速度。这并不一定是不利的。Rust 还保证当编译器检查每个数据指针时,你不会遇到内存安全性错误。对于复杂的系统,此保证会派上用场。

在以下情况下选择 Rust:

  • 你特别关心性能
  • 你想要对线程进行细粒度的控制
  • 你重视内存安全而不是简单性

Go vs. Rust:真实想法

让我们从突出相似之处开始。Go 和 Rust 都是开源的,旨在支持微服务架构和并行计算环境。两者都通过并发优化了可用 CPU 内核的利用率。

但归根结底,哪种语言更好?

有很多方法可以解决这个问题。我建议考虑要构建哪种类型的应用程序。Go 可很好地用于创建 Web 应用程序和 API,这些应用程序和 API 利用其内置的并发功能,同时支持微服务体系结构。

你也可以使用 Rust 来开发 Web API,但并不是在 Rust 设计时考虑到的场景。Rust 对内存安全性的关注增加了复杂性和开发时间,尤其是对于相当简单的 Web API。但是,对代码的大量控制使你可以编写更优化,内存效率更高且性能更高的代码。

简而言之,Go 与 Rust 的争论实际上是一个简单与安全的问题。

Go vs. Rust,你的选择呢?

作者:Michiel Mulders,原文链接:https://blog.logrocket.com/when-to-use-rust-and-when-to-use-golang/

参考资料

[1]

该初学者指南: https://blog.logrocket.com/getting-up-to-speed-with-rust/

[2]

基准测试: https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/rust-go.html

[3]

Bitbucket: https://bitbucket.org/blog/why-rust

[4]

bechmarksgame: https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/rust-go.html

[5]

可证明正确的并发: https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html

[6]

通道: https://doc.rust-lang.org/stable/rust-by-example/std_misc/channels.html

[7]

指针: https://doc.rust-lang.org/std/primitive.pointer.html

[8]

锁: https://doc.rust-lang.org/std/sync/struct.Mutex.html

[9]

使用 Rust 进行无所畏惧的并发: https://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html

[10]

类型安全: https://en.wikipedia.org/wiki/Type_safety

[11]

Bitbucket 博客: https://bitbucket.org/blog/why-rust

[12]

Loris Cro: https://kristoff.it/blog/why-go-and-not-rust/




往期推荐


我是 polarisxu,北大硕士毕业,曾在 360 等知名互联网公司工作,10多年技术研发与架构经验!2012 年接触 Go 语言并创建了 Go 语言中文网!著有《Go语言编程之旅》、开源图书《Go语言标准库》等。


坚持输出技术(包括 Go、Rust 等技术)、职场心得和创业感悟!欢迎关注「polarisxu」一起成长!也欢迎加我微信好友交流:gopherstudio

浏览 165
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报