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

正如我们从2010年的 计算机语言基准游戏中看到的:

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

How can this be, bearing in mind that Go compiler produces native code for execution?
围棋编译器不成熟? 还是围棋语言存在一些固有的问题?

EDIT:
大多数答案都否认了 Go 语言固有的缓慢性,声称问题存在于不成熟的编译器中。
因此,我做了一些自己的测试 计算斐波那契数: 迭代算法运行在 Go (freebsd,6 g)中,其 same速度与 C (使用 O3选项)一样。在 Go 2 times中,无趣的递归运行速度比 C 慢(带-O3选项; 带-O0选项-相同)。但我没有看到10倍的下降,在基准游戏。

55777 次浏览

6g 和8g 编译器不是特别优化,所以它们生成的代码也不是特别快。

They're designed to run fast themselves and produce code that's OK (there is a bit of optimisation). gccgo uses GCC's existing optimisation passes, and might provide a more pointful comparison with C, but gccgo isn't feature-complete yet.

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

FWIW,我自己用 Go 做的一个非常简单的测试,当我看它的时候(基本上是一个整数加法的循环) ,gccgo 生成的代码接近于 gcc -O0gcc -O2之间的快速终端。 Go 本身并不慢,但是编译器还没有完成所有的工作。对于一门10分钟的语言来说,这并不奇怪。

常见问题解答的下一个版本中,应该会出现类似于以下内容的内容。

表演

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

Go 的设计目标之一是 接近 C 的性能 可比较的程序,但在一些 基准是它做得很差, 包括几个在试验/试验台 最慢的依赖于库 versions of comparable performance are 在 Go 中不可用。例如, Pidigits 依赖于多精度 数学软件包和 C 语言版本, 与 Go’s 不同的是,使用 GMP (这是编写的 in optimized assembler). Benchmarks 依赖于正则表达式的 (例如,regex-dna)是 本质上是比较围棋的权宜之计 Regexp 包要成熟,高度 优化的正则表达式库 比如 PCRE。

基准游戏的赢家是广泛的 以及大部分的 Go 版本 the benchmarks need attention. If you 衡量可比较的 C 和 Go 程序 (反向补语是一个例子) , 你会发现这两种语言 更接近原始表现 套件会显示。

不过,仍有改进的空间。 编译器很好,但也有可能是 更好的是,许多图书馆需要主修 表演工作,和垃圾 收集器还不够快(甚至 如果是的话,小心不要 产生不必要的垃圾 一个巨大的影响)。

这里有一些关于 计算机基准游戏的更多细节,来自最近的一个邮件列表帖子。

Gccgo 中的垃圾收集和性能(1)

Gccgo 中的垃圾收集和性能(2)

值得注意的是,计算机基准游戏只是一个游戏。在性能测量和容量规划方面有经验的人会仔细地匹配真实和实际的工作负载,他们不会玩游戏。

我的回答并不像其他人的那么专业,但我认为它仍然有意义。 当我决定开始学围棋的时候,我在计算机基准游戏中看到了同样的基准。但老实说,我认为所有这些合成基准对于确定 Go 是否对你来说足够快是毫无意义的。

最近,我使用 Torado + TornadIO + ZMQ 用 Python 编写了一个消息服务器,对于我的第一个 Go 项目,我决定用 Go 重写服务器。到目前为止,服务器已经具备了与 Python 版本相同的功能,我的测试显示 Go 程序的速度提高了大约4.7倍。提醒你一下,我只用 Go 编写了一个星期的代码,而且我用 Python 编写代码已经超过5年了。

Go is only going to get faster as they continue to work on it, and I think really it comes down to how it performs in a real world application and not tiny little computational benchmarks. For me, Go apparently resulted in a more efficient program than what I could produce in Python. That is my take on the answer to this question.

Java 和 C 的数据和方法(函数)定义更加明确。C 是静态类型的,而 Java 的继承模型则不是这样。这意味着数据的处理方式在编译过程中基本上是定义好的。

Go 的数据和函数定义更加隐式。内置函数在本质上更加通用,而且缺乏类型层次结构(如 Java 或 C + +)使 Go 在速度上处于劣势。

请记住,谷歌围棋语言的目标是在执行速度和编码速度之间达成一个可以接受的折衷。我认为他们在早期的尝试中达到了一个很好的最佳点,只有更多的工作完成了,情况才会有所改善。

如果你比较围棋与更多的动态类型语言的主要优势是编码速度,你会看到围棋的执行速度优势。Go 比 perl 快8倍,比 Ruby 1.9和 Python 3在您使用的基准上快6倍。

不管怎样,更好的问题应该是 Go 在编程简单性和执行速度方面是一个很好的折衷方案?我的回答是肯定的,情况应该会好转。

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

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

请注意,在 螺纹环基准螺纹环基准中,Go 比 Java 快。在同样的场景中,Go CSP 几乎与 C + + 相当,但使用的内存少了4倍。

围棋语言的强大之处在于它的并发模型,交谈循序程式,CSP,由托尼 · 霍尔在70年代指定,实现简单,适合高度并发的需求。

一切都变了。

我认为目前对你的问题的正确答案是反驳“前进是缓慢的”的观点。在您询问的时候,您的判断是合理的,但是去已经获得了很多方面的表现。现在,它仍然没有 C 那么快,但是从一般意义上来说,没有接近10倍的速度。

计算机语言基准测试游戏

在撰写本文时:

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%

Though, it does suffer brutally on the binary tree benchmark:

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%

Java 比 Go 和 C + + 快,并且在很多情况下比 C 快,有两个基本原因:

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

2) The GC. GC based memory allocation is nearly free, as compared to malloc. And the 'free' penalty can be amortized across the entire runtime - often skipped because the program terminates before all garbage needs to be collected.

There are hundreds (thousands?) of extremely talented developers making the GC/JVM efficient. Thinking you can "code better than all of them" is a folly. It is a human ego problem at its heart - humans have a hard time accepting that with proper training by talented humans, the computer is going to perform better than the humans that programmed it.

顺便说一句,如果你不使用面向对象的特性,C + + 可以和 C 一样快,但是你很快就可以开始用 C 编程了。

最重要的是,这些测试中的“速度差异”通常是没有意义的。IO 成本的数量级大于性能差异,因此,使 IO 成本最小化的正确设计总是赢家——即使是在一个直译语言中。很少有系统是 CPU 绑定的。

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

As a final, final note... I ran the tests using Go, and it was 7.9 secs. The fact that when you click on Go, it compares it to Java, and when you click on Java it compares it to C, should be a red flag to any serious engineer.

对于 Java、 Go 和 C + + 的实际比较,请参阅 https://www.biorxiv.org/content/10.1101/558056v1剧透警告,Java 在原始性能方面名列前茅,Go 在内存使用和挂起时间方面名列前茅。

事实上,Go 不仅在设计时优雅高效,而且在运行时表现出色。关键是要使用正确的操作系统,即 LINUX。在 Windows 和 Mac 操作系统下的性能分析结果,用一个更好的词来形容的话,就是差了一两个数量级。

under linux, the go runtime is super fast, perfectly comparable with c/c++. the go runtime under windows and unix are not in the same league

与 java 的比较并不那么重要,去是为了系统和应用程序开发(因为 java 更像是应用程序开发的蓝领)。不会进入细节,但当像库伯内特这样的东西写在去,你意识到这不是一个企业顾问友好的玩具

我不记得谷歌提到过一次你提到的妥协。Go 设计良好,简单、优雅、高效,适用于设计系统和应用程序级别的程序,具有指针、高效的内存分配和释放,避免了由于容易错过实现继承而产生的复杂性,为您提供了协同例程和其他现代方式,可以在时间和预算上编写高性能的应用程序。同样,go 在 linux 下非常快,这正是它设计的目的(非常高兴它做到了)