为什么Go这么慢(与Java相比)?

问题描述 投票:108回答:10

正如我们在2010年从The Computer Language Benchmarks Game看到的那样:

  • Go平均比C慢10倍
  • Go比Java慢3倍!

考虑到Go编译器生成用于执行的本机代码,这怎么可能呢? Go的不成熟的编译器?或者Go语言存在一些内在问题?

编辑: 大多数答案否认Go语言的内在缓慢,声称问题存在于不成熟的编译器中。 因此我做了一些自己的测试to calculate Fibonacci numbers:迭代算法在Go(freebsd,6g)中运行,其中same速度与C一样(使用O3选项)。沉闷的递归运行在Go 2 times中比在C中慢(使用-O3选项;使用-O0 - 相同)。但我没有看到基准游戏中的10倍跌幅。

java performance go benchmarking
10个回答
100
投票

6g和8g编译器没有特别优化,因此它们生成的代码不是特别快。

它们被设计为自己快速运行并生成可以正常运行的代码(有一些优化)。 gccgo使用GCC现有的优化通道,并且可能提供与C的更有意义的比较,但gccgo尚未完成功能。

基准数字几乎完全与实施质量有关。它们与语言本身并没有太大关系,除非实现花费运行时支持基准测试并不真正需要的语言功能。在大多数编译语言中,一个足够聪明的编译器理论上可以删除不需要的东西,但是有一个点你需要操作演示,因为很少有真正的语言用户会编写没有使用该功能的程序。在不完全删除它们的情况下将事物移开(例如,在JIT编译的Java中预测虚拟调用目标)开始变得棘手。

FWIW,当我看一下它(基本上是一个整数加法的循环)时,我自己非常琐碎的测试,gccgo生成的代码朝着gcc -O0gcc -O2之间的范围的快速结束等同的C. Go本身并不是虽然很慢,但编译器并没有做任何事情。对于一种10分钟的语言来说,这简直令人惊讶。


-4
投票

Java和C都有更明确的数据和方法(函数)定义。 C是静态类型的,其继承模型的Java较少。这意味着在编译期间几乎定义了数据的处理方式。

Go的数据和函数定义更加隐含。内置函数本质上更通用,缺少类型层次结构(如Java或C ++)使Go速度不利。

请记住,Google的Go语言目标是在执行速度和编码速度之间达成可接受的折衷。我认为他们在早期尝试中获得了一个很好的好处,事情只会随着更多的工作而改善。

如果将Go与更具动态类型的语言进行比较,其主要优点是编码速度,您将看到Go的执行速度优势。在你使用的那些基准测试中,Go比perl快8倍,比Ruby 1.9和Python 3快6倍。

无论如何,更好的问题是在编程的简易性和执行速度方面做出妥协?我的回答是肯定的,应该会变得更好。


50
投票

Go FAQ的下一个版本中,应该出现类似于以下内容的内容。

性能

为什么Go在基准X上表现不佳?

Go的设计目标之一是为可比较的程序接近C的性能,但在某些基准测试中,它的表现相当差,包括测试/工作台中的几个。最慢的依赖于库,Go中没有可用性能相当的库。例如,pidigits依赖于多精度数学包,而C版本与Go不同,使用GMP(用优化的汇编程序编写)。依赖于正则表达式的基准(例如regex-dna)本质上是将Go的stopgap regexp包与成熟的,高度优化的正则表达式库(如PCRE)进行比较。

通过广泛的调整赢得基准游戏,大多数基准测试的Go版本需要引起注意。如果你测量可比较的C和Go程序(反向补充是一个例子),你会发现两种语言的原始性能比这个套件所表明的要接近得多。

不过,还有改进的余地。编译器很好但可能更好,许多库需要主要的性能工作,垃圾收集器还不够快(即使它是,注意不要产生不必要的垃圾会产生巨大的影响)。

以下是来自最近邮件列表主题的The Computer Benchmarks Game的更多细节。

Garbage collection and performance in gccgo (1)

Garbage collection and performance in gccgo (2)

值得注意的是,计算机基准游戏只是一款游戏。具有性能测量和容量规划经验的人员可以像现实和实际工作负载一样仔细匹配;他们不玩游戏。


34
投票

我的回答并不像其他人那样技术性,但我认为它仍然具有相关性。当我决定开始学习Go时,我在计算机基准游戏中看到了相同的基准。但老实说,我认为所有这些综合基准测试在决定Go是否足够快的方面毫无意义。

我最近使用Tornado + TornadIO + ZMQ在Python中编写了一个消息服务器,对于我的第一个Go项目,我决定在Go中重写服务器。到目前为止,让服务器具有与Python版本相同的功能,我的测试向我展示了Go程序中4.7倍的速度提升。请注意,我只在Go中编写了一个星期的代码,而且我已经用Python编写了超过5年的编码。

Go只会在它们继续工作时变得更快,我认为它实际上归结为它在现实世界的应用程序中的表现,而不是微小的计算基准。对我来说,Go显然比我在Python中生成的程序更有效。这是我对这个问题的回答。


6
投票

事情变了。

我认为你问题的当前正确答案是反对这样做的观点。在你的询问时,你的判断是合理的,但从那以后,在表现方面取得了很多进展。现在,它仍然没有C那么快,但是在一般意义上,它不会慢近10倍。

Computer language benchmarks game

在撰写本文时:

source  secs    KB      gz      cpu     cpu load

reverse-complement
1.167x
Go      0.49    88,320  1278    0.84    30% 28% 98% 34%
C gcc   0.42    145,900 812     0.57    0% 26% 20% 100%

pidigits
1.21x
Go      2.10    8,084   603 2.10    0% 100% 1% 1%
C gcc   1.73    1,992   448 1.73    1% 100% 1% 0%

fasta
1.45x
Go      1.97    3,456   1344    5.76    76% 71% 74% 73%
C gcc   1.36    2,800   1993    5.26    96% 97% 100% 97%

regex-dna
1.64x
Go      3.89    369,380 1229    8.29    43% 53% 61% 82%
C gcc   2.43    339,000 2579    5.68    46% 70% 51% 72%

fannkuch-redux
1.72x
Go      15.59   952 900 62.08   100% 100% 100% 100%
C gcc   9.07    1,576   910 35.43   100% 99% 98% 94%

spectral-norm
2x
Go      3.96    2,412   548 15.73   99% 99% 100% 99%
C gcc   1.98    1,776   1139    7.87    99% 99% 100% 99%

n-body
2.27x
Go      21.73   952 1310    21.73   0% 100% 1% 2%
C gcc   9.56    1,000   1490    9.56    1% 100% 1% 1%

k-nucleotide
2.40x
Go      15.48   149,276 1582    54.68   88% 97% 90% 79%
C gcc   6.46    130,076 1500    17.06   51% 37% 89% 88%

mandelbrot
3.19x
Go      5.68    30,756  894 22.56   100% 100% 99% 99%
C gcc   1.78    29,792  911 7.03    100% 99% 99% 98%

虽然,它在二叉树基准测试中遭受残酷的打击:

binary-trees
12.16x
Go      39.88   361,208 688 152.12  96% 95% 96% 96%
C gcc   3.28    156,780 906 10.12   91% 77% 59% 83%

5
投票

尽管围绕CPU周期使用效率不是很高,但Go并发模型比Java中的线程模型快得多,并且可以与C ++线程模型相媲美。

请注意,在thread-ring benchmark中,Go比Java快16倍。在相同的场景中,Go CSP几乎与C ++相当,但使用的内存减少了4倍。

Go语言的强大功能是它的并发模型,即70年代由Tony Hoare指定的通信顺序进程,CSP,易于实现并适合高度并发的需求。


1
投票

我认为一个经常被忽视的事实是,JIT编译可以是>静态编译,尤其是(运行时)后期绑定函数或方法。热点JIT在RUNTIME决定采用哪种内联方法,甚至可以将数据布局调整为当前运行的CPU的高速缓存大小/体系结构。通过直接访问硬件,C / C ++通常可以弥补(并且总体上仍将表现更好)。对于Go来说,事物可能看起来不同,因为它与C相比更高级,但目前缺少运行时优化系统/编译器。我的直觉告诉我,Go可能比Java更快,因为Go不强制指针追逐那么多,并鼓励更好的数据结构局部性+需要更少的分配。


1
投票

Java比Go和C ++更快有两个基本原因,在许多情况下可能比C更快:

1)JIT编译器。它可以基于运行时配置文件通过多个级别内联虚拟函数调用,即使使用OO类也是如此。这在静态编译的语言中是不可能的(尽管基于记录的配置文件的较新的重新编译可以提供帮助)。这对涉及重复算法的大多数基准测试非常重要。

2)GC。与malloc相比,基于GC的内存分配几乎是免费的。并且“免费”惩罚可以在整个运行时间内分摊 - 经常被跳过,因为程序在需要收集所有垃圾之前终止。

有数百(数千?)非常有才华的开发人员使GC / JVM高效。认为你可以“比所有人更好地编码”是一种愚蠢的行为。这是一个人类自我问题的核心 - 人类很难接受通过有才能的人类的适当训练,计算机将比编程它的人类表现更好。

顺便说一下,如果不使用和使用OO功能,C ++可以和C一样快,但是接下来你就开始编写C语言了。

最重要的是,这些测试中的“速度差异”通常毫无意义。 IO成本比性能差异高出几个数量级,因此最小化IO成本的正确设计总能获胜 - 即使是在解释性语言中也是如此。很少有系统受CPU限制。

最后,人们将“计算机语言基准游戏”称为“科学测量”。测试是完全有缺陷的,例如,如果您查看nbody的Java测试。当我在相同的操作系统/硬件上运行测试时,Java大约需要7.6秒,C大约需要4.7秒 - 这是合理的 - 而不是测试报告的4倍慢。它是点击诱饵,虚假新闻,旨在产生网站流量。

作为最终的,最后的注释......我使用Go运行测试,它是7.9秒。事实上,当你单击Go时,它将它与Java进行比较,当你点击Java时它将它与C进行比较,应该是任何严肃的工程师的红旗。

对于Java,Go和C ++的现实世界比较,请参阅https://www.biorxiv.org/content/10.1101/558056v1扰流警报,Java在原始性能方面名列前茅,Go结合了内存使用和壁挂时间。


1
投票

事实上,Go不仅在设计时优雅高效,而且在运行时也具有超高性能。关键是使用正确的操作系统,即LINUX。 Windows和Mac OS下的性能分析结果是,由于缺少一个更好的词,比一个或两个数量级更差。


0
投票

在linux下,go运行时超快,与c / c ++完全可比。 windows和unix下的go运行时不属于同一个联盟

与java的比较并不那么重要,go用于系统和应用程序开发(因为java更像是仅用于应用程序开发的蓝领)。不会详细介绍,但是当像kubernetes这样的东西写进去时,你会发现这不是一个企业顾问友好的玩具

我不记得谷歌提到甚至一次你提到的妥协。 go设计精良,简单,优雅,高效,适用于设计系统和应用程序级程序,具有指针,高效的内存分配和解除分配,避免了由于易于错过使用的实现继承而产生的复杂性,为您提供协同例程和其他现代化在时间和预算上编写高性能应用程序的方法。再一次,go在linux下超级快,这正是它的设计目标(非常高兴它确实如此)

© www.soinside.com 2019 - 2024. All rights reserved.