到底谁才是处理高并发最快的:Rust vs Go vs Java vs Node.js vs Deno vs .NET 6

6,924 阅读5分钟

image.png 上图,比较了当下比较流行的编程语言如Rust, Go, JavaScript (NodeJS), TypeScript (Deno), 和 Java等,对于高并发请求的处理速度,分别从多线程、异步、异步多线程三个维度进行了比较,单仅从异步处理维度来看,Rust是最快的,但是没想到Java的速度比GO还要快!!!当然JS和TS的异步处理是最慢的😂······

什么是并发(concurrency)?

并发是编程中最复杂的一面,并且不同的编程语言,并发的复杂程度可能是“这也太让人困惑了”,也可能是让你惊叹“这到底什么黑魔法”

并发是一种能够在同一时间处理多个任务的能力,没有特定的顺序,也不会影响最后的输出结果。并发是一个非常广泛的术语,可以通过多线程(multi-threading)、并行(parallelism)或异步处理(asynchronous process)来实现。

image.png

对比测试

前提条件:以下测试都是基于java、node、go、rust搭建的web服务器,为了尽量客观公正,这些服务器都尽可能少的使用第三方依赖,同时测试代码都一样。

用来语言测试的各版本号如下:

  • Rust: 1.58.1-Stable
  • Go: 1.17.6
  • Java: OpenJDK 17.0.2
  • Node.js: 17.4.0
  • Deno: 1.18.1
  • .NET: 6.0.100

如果一个编程语言同时支持异步和多线程,我们将测试二者,并且取其中性能最好的一个作为比较结果。一个应用程序的复杂度,取决于你所选的编程语言的特性和复杂度,但是该项测试不考虑复杂度,而是尽可能利用语言所能提供的最大化的处理并发的能力,比如有些语言会提供Promise、线程池、worker等等......

郑重声明,该项测试并不是声称这是一种准确的科学方法,也不是并发的最佳标准。在不同的使用用例或者场景中,可能会有不一样的结果,并且在实际开发中,这只会更复杂。这里测试比较的只是一些最简单最基本的用例,所以不能以偏概全。

所有的实现,具体的测试代码,都在这个仓库

测试结果

测试结果都来自于wrk, drill这些基准测试工具。

wrk测试结果

wrk测试8线程,500次连接,间隔30s时候的性能:

wrk -t8 -c500 -d30s http://127.0.0.1:8080  

image.png

image.png

dril测试结果

drill 测试1000次和1百万次时候的并发请求:

image.png

image.png

结果

  • wrk工具测试的HTTP请求中,GO在 请求/秒、延迟、吞吐量方面完胜,但是GO比Rust占用了更多的内存和CPU。但如果比较 Go HTTP、 Rust activex-web 和 Java Undertow,令人惊讶的是 Undertow 表现得更好,而 activex-web 排在第二位。
  • GO TCP与Rust和Java进行比较,在这种情况下,Java和Rust均优于GO,所以上一个HTTP请求,GO完胜有可能是因为内置的HTTP库比较优秀,所以我们有理由相信肯定会有一个更优秀的第三方HTTP库能够让Rust胜过Go。
  • 换个角度来比较下资源使用情况,在所有的基准测试中,Rust用的内存和CPU是最少的,Java占用的内存最多,Node多线程用的CPU最多。
  • 异步Rust比多线程Rust,来处理高并发性能更好
  • 在使用drill工具的基准测试中,异步 Java 优于 Rust!!
  • Java 和 Deno失败的请求比其它更多
  • 从1000增加到2000次的高并发请求中,很多语言都会有失败请求,Go HTTP 和 Rust Tokio奖金百分百会出现失败请求!但是多线程的Node失败率却是最低的,并且还具有良好的性能,但是它V8引擎使用的CPU是最高的。
  • Node的性能比Deno要好

简易性

相比于盲目追求极致的性能,一个语言是否简单、易用也是很重要的。所以对于异步还是多线程的选择也很关键

异步

个人认为 Node.js 和 Deno 是异步处理并发最简单的!Go是我的第二选择,因为它也很容易使用,没有妥协的功能或性能。Rust紧随其后,但是稍微更加复杂的,因为它有更多的特点需要习惯。我认为 Java 是最后一个,因为它需要更多的模板,而且异步编程比其他编程更复杂。

多线程

对于多线程处理高并发的请求,首推Rust,因为它包含了很多功能,并且在 Rust 中执行多线程是简单和不用慌的,这是由于内存和线程安全。但是Java成熟的生态系统,使得其多线程也不难使用。GO是使用最简单的,如果你对线程控制要求不高,那么我更推荐GO而不是Java。至于Node和Deno,由于其多线程处理的灵活性不如其它,所以放在最后。

生态环境

Rust在处理并发请求方面有着最好的生态环境,其次是Java和Go,也有着成熟的生态系统。至于Node和Deno相对而言社区生态就没有那么完善了。

参考文章: Concurrency in modern programming languages: Rust vs Go vs Java vs Node.js vs Deno vs .NET 6 | Technorage (deepu.tech)