为了节省您的宝贵时间,直接上结果。 每秒请求数量,越高越好 这篇文章是关于多个现代编程语言的并发性能对比,对比意义有助于您选择技术栈构建现代多人网络服务,我们将在其中讨论现代编程语言中的并发性。首先将构建一个并发Web服务器,然后对其进行基准测试,该服务器的灵感来自Rust书中的示例,使用的是Rust、Go、JavaScript(NodeJS)、TypeScript(Deno)、Kotlin和Java等流行语言,来比较这些语言平台之间的并发性及其性能。(书中例子如下链接) https:doc。rustlang。orgbookch2000finalprojectawebserver。html什么是并发 并发性是编程中最复杂的方面之一,根据您选择的语言,复杂性可以从看起来令人困惑到这是什么黑魔法呀。 并发性是指可以在重叠的时间段内以特定顺序执行多个任务而不影响最终结果的能力。并发是一个非常广泛的术语,可以通过多线程、并行性和或异步处理来实现。 图1,在单核上下文切换中并发任务(多线程)图2,在多核下多任务并发(并行)基准测试和比较 我们尽可能保持简单,而不是尽可能多地使用外部依赖项。首先在各种语言中保持了相似的代码。在这篇文章中,我们将比较所有这些实现的性能,以了解哪种语言为并发Web服务器提供了最佳性能。 如果语言同时支持异步和多线程并发,我们将尝试两者以及两者的组合,并选择表现最佳的进行比较。因此,应用程序的复杂性将取决于语言功能和语言复杂性。我们将使用语言提供的任何内容,以使并发性能尽可能好,而不会使事情过于复杂。Web服务器将只为一个终端节点提供服务。 如果需要并且语言支持,我们将使用Promise,线程池和worker。我们不会在应用程序中使用任何不必要的东西IO。 代码实现可能不是最好的;如果您有改进建议,请在本篇文章评论。进一步的改进包括:将线程池用于Java多线程版本使用JavaWeb服务器库使用createReadStreamforNode。js添加了一个Rustactixweb示例来进行比较 免责声明:并不是说这是一种准确的科学方法或并发的最佳基准。我们很确定不同的用例会产生不同的结果,并且实际的Web服务器将具有更高的复杂性,需要并发进程之间的通信,从而影响性能。我们只是试图为一个简单的用例提供一些简单的基础比较。此外,我对某些语言的了解比其他语言更好。因此,可能会在这里和那里错过一些优化。如果您认为可以开箱即用地改进特定语言的代码以增强并发性能,请告诉我。如果您认为此基准测试无用,那么,请建议一个更好的基准:) 基准测试条件 这些将是我将用于基准测试的一些条件。使用可用语言运行时的最新稳定发行版本,在撰写本文时: Rust:1。58。1Stable Go:1。17。6 Java:OpenJDK17。0。2 node。js:17。4。0 deno:1。18。1 。NET:6。0。100仅当外部依赖项是该语言中的标准推荐方式时,我们才会使用外部依赖项。在撰写本文时,将使用此类依赖项的最新版本我们不会考虑使用任何配置调整来提高并发性能更新:许多人指出,ApacheBench并不是这个基准测试的最佳工具。因此,我还包括了wrk和drill的结果我们将使用ApacheBench进行具有以下设置的基准测试: 1。100个请求的并发factor 2。总数为10000个请求 3。本次基准测试将针对每种语言进行十次warmup,并采用平均值。 4。ApacheBench版本(Fedora):httpdtools2。4。521。fc35。x8664 5。使用的命令:abc100n10000http:localhost:8080所有基准测试均在运行Fedora35的同一台计算机上运行,该机器采用英特尔i911900H(8核16线程)处理器,内存为64GB。客户端从同一网络上的另一台类似的计算机运行,也从同一台计算机运行。结果或多或少是相同的;我使用客户端计算机的结果进行比较。wrkdrill比较参数 我还将比较以下与并发相关的方面。性能,基于基准测试结果社区共识易用性和简单性,特别是对于复杂的用例用于并发的外部库和生态系统基准测试结果 更新:我已经用wrk,drill的结果更新了基准测试结果,并在各种人建议的调整后更新了ApacheBench的先前结果。 更新2:现在存储库中只有一个。NET6版本,这要归功于PR的srollinet。基准测试更新了。NET结果。 更新3:使用actixweb和Javaundertow的Rust现在包含在和基准测试中。这些实现被简化为仅返回一个字符串,而不是为这些字符串执行文件IO,因此它们显示为一个单独的集合。我将此系列作为语言并发实验开始。现在,这感觉就像是Web服务器框架的基准;虽然并发性是其中的一个重要方面,但我不确定结果是否意味着语言方面的并发性。wrkdrill来自wrk的结果 使用以下命令进行基准测试(线程8,连接500,持续时间30秒):wrk1wrkt8c500d30shttp:127。0。0。1:8080 GoHTTP、Rustactixweb、JavaUndertow和。NET6的更新比较 Go,Rust和JavaWeb服务器版本在要求秒性能方面将一切都吹得沸沸扬扬扬。如果我们删除它,我们会得到更好的图片,如下所示。 drill结果 使用并发1000和100万个请求进行基准测试drill GoHTTP、Rustactixweb、JavaUndertow和。NET6的更新比较 使用并发2000和100万个请求进行基准测试drill GoHTTP、Rustactixweb、JavaUndertow和。NET6的更新比较 上一篇ApacheBench结果与线程阻塞 在十个基准测试运行中每十个请求一次的不同指标的平均值如下所示:thread。sleep 您可以找到GitHub存储库中使用的所有结果结论 根据基准测试结果,这些是我的观察结果。基准观察 由于基于基准的建议是热门话题,我们只分享出观察结果,您可以自己做出决定。对于使用的HTTP服务器基准测试,GoHTTP在请求秒、延迟和吞吐量方面获胜,但它比Rust使用更多的内存和CPU。这可能是因为Go拥有最好的内置HTTP库之一,并且它经过了极高的调整,以获得最佳性能;因此,将其与我为Java和Rust所做的简单TCP实现进行比较是不公平的。但是你可以将其与Node。js和Deno进行比较,因为它们也有标准的HTTP库,在这里用于基准测试。更新:我现在已经将GoHTTP与Rustactixweb和JavaUndertow进行了比较,令人惊讶的是Undertow表现更好,actixweb排在第二位。也许像Gin这样的GoWeb框架将更接近Undertow和actixweb。wrkGoTCP版本与Rust和Java实现进行了公平的比较,在这种情况下,Java和Rust都优于Go,因此期望Rust和Java中的第三方HTTP库可以与Go竞争是合乎逻辑的,如果我是一个打赌的人,我会打赌有一个Rust库可以胜过Go。资源使用是一个完全不同的故事,Rust似乎在所有基准测试中始终使用最少的内存和CPU,而Java使用最多的内存,而Node。js多线程版本使用最多的CPU。异步Rust的性能似乎比多线程强Rust实现差。在使用的基准测试中,异步Java版本优于Rust,这对我来说是一个惊喜。drillJava和Deno的失败请求比其他的要多。当并发请求从1000个增加到2000个时,大多数实现的失败率都非常高。GoHTTP和RustTokio版本的故障率接近100,而多线程Node。js的故障最少,并且在该并发级别具有良好的性能,但CPU使用率很高。它运行多个版本的V8进行多线程处理,这解释了CPU使用率高的原因。总体而言,Node。js似乎仍然比Deno表现更好。另一个重要的收获是,像ApacheBench,wrk或drill这样的基准测试工具似乎提供了非常不同的结果,因此微观基准测试不如最终的性能基准可靠。根据实际用例和特定于实现的详细信息,可能会有很多差异。感谢EamonNerbonne指出这一点。Apache基准测试在有和没有的版本上运行并不能说明什么,因为所有实现的结果都是相似的,这可能是由于ApacheBench工具的限制。因此,正如许多人指出的那样,我无视他们。thread。sleep 有关Web框架的更全面的基准测试,我建议查看TechEmpower的Web框架基准测试社区共识 在并发性能方面,社区共识是相当分裂的。例如,Rust和Go社区都声称在并发性能方面是最好的。从个人经验来看,我发现它们在性能上相对接近,Rust略微领先于Go。Node。js生态系统建立在异步并发性能的承诺之上,并且有证据表明,在切换到Node。js时,性能会大幅提高。Java还拥有现实世界的项目,可以毫无问题地为数百万个并发请求提供服务。因此,很难在这里站出来。 另一个普遍的观察结果是,Rust在跨运行的性能方面非常一致,而所有其他语言都有一些差异,特别是当GC启动时。单纯 虽然性能是一个重要方面,但易用性和简单性也非常重要。我认为区分异步和多线程方法也很重要。 异步:我个人认为Node。js和Deno是最简单,最易于使用的异步并发平台。Golang将是我的第二选择,因为它也易于使用和简单,而不会影响功能或性能。Rust遵循它,因为它有点复杂,因为它具有更多的功能和需要习惯。我认为Java排在最后,因为它需要更多的样板,并且进行异步编程比其他代码更复杂。我希望ProjectLoom能够为Java解决这个问题。 多线程:对于多线程并发,我将把Rust放在第一位,因为它充满了功能,并且由于内存和线程安全性,在Rust中执行多线程操作既简单又无忧。您不必担心竞争条件等。我会把Java和Go放在第二位。Java拥有成熟的多线程生态系统,使用起来并不难。Go非常易于使用,但是您对操作系统线程没有太多控制,否则我会将Go评为高于Java。最后,Node。js和Deno中具有多线程功能,但它们不如其他语言灵活;因此,我将把它们放在最后。生态系统 在我看来,Rust拥有最好的并发生态系统,其次是Java和Golang,它们已经有了成熟的选择。Node。js和Deno虽然不如其他节点好,但也提供了一个底层的生态系统。