为什么Go语言相对于Java来说速度很慢?

huangapple go评论119阅读模式
英文:

Why is Go so slow (compared to Java)?

问题

The Computer Language Benchmarks Game中我们可以看到,2010年的情况是:

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

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

编辑:
大多数回答都否认Go语言本身的内在缓慢性,声称问题在于编译器还不成熟。
因此,我进行了一些自己的测试计算斐波那契数列:在Go(freebsd,6g)中,迭代算法的运行速度与C(使用O3选项)相同。而愚蠢的递归算法在Go中运行比C慢2倍(使用-O3选项;使用-O0时相同)。但我没有看到像在Benchmark Game中那样的10倍下降。

英文:

As we could see from The Computer Language Benchmarks Game in 2010:

  • Go is on average 10x slower than C
  • Go is 3x slower than Java !?

How can this be, bearing in mind that Go compiler produces native code for execution?
Immature compilers for Go? Or there is some intrinsic problem with the Go language?

EDIT:
Most answers deny intrinsic slowness of Go languge, claiming the problem resides in immature compilers.
Therefore I've made some own tests to calculate Fibonacci numbers: Iterative algorithm runs in Go (freebsd,6g) with the same speed as in C (with O3 option). The dull recursive one runs in Go 2 times slower than in C (with -O3 option; with -O0 - the same). But I haven't seen 10x fall as in the Benchmarks Game.

答案1

得分: 104

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

它们被设计成自己运行得很快,并生成可以接受的代码(有一些优化)。gccgo使用GCC现有的优化步骤,可能会提供一个更有意义的与C的比较,但是gccgo还没有完全实现所有功能。

基准测试数据几乎完全取决于实现的质量。它们与语言本身几乎没有太大关系,除非实现在运行时支持基准测试实际上并不需要的语言特性。在大多数编译语言中,一个足够聪明的编译器理论上可以剥离不需要的部分,但是到了某个程度,你就在操纵演示了,因为很少有真正使用该语言的用户会编写不使用该特性的程序。将事物移出路径而不完全删除它们(例如,在JIT编译的Java中预测虚拟调用目标)开始变得棘手。

顺便说一下,当我看Go时进行的非常简单的测试(基本上是一个整数加法的循环),gccgo生成的代码在与等效的C的gcc -O0gcc -O2之间的快速端之间。Go本身并不慢,但编译器还没有做到一切。对于一个刚刚诞生10分钟的语言来说,这并不奇怪。

英文:

The 6g and 8g compilers are not particularly optimising, so the code they produce isn't particularly fast.

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.

Benchmark figures are almost entirely about quality of implementation. They don't have a huge amount to do with the language as such, except to the extent that the implementation spends runtime supporting language features that the benchmark doesn't really need. In most compiled languages a sufficiently clever compiler could in theory strip out what isn't needed, but there comes a point where you're rigging the demo, since very few real users of the language would write programs that didn't use that feature. Moving things out of the way without removing them entirely (e.g. predicting virtual call destinations in JIT-compiled Java) starts to get tricky.

FWIW, my own very trivial test with Go when I was taking a look at it (a loop of integer addition, basically), gccgo produced code towards the fast end of the range between gcc -O0 and gcc -O2 for equivalent C. Go isn't inherently slow, but the compilers don't do everything, yet. Hardly surprising for a language that's 10 minutes old.

答案2

得分: 53

在下一个Go FAQ的发布中,应该会出现类似以下内容的东西。

> 性能
>
> 为什么Go在基准测试X上表现不佳?
>
> Go的设计目标之一是接近C的性能,用于可比较的程序,但在一些基准测试中,它表现得相当差,包括test/bench中的几个。最慢的基准测试依赖于在Go中没有可比性能版本的库。例如,pidigits依赖于一个多精度数学包,而C版本则使用了GMP(它是用优化的汇编语言编写的)。依赖于正则表达式的基准测试(例如regex-dna)基本上是将Go的临时正则表达式包与成熟的、高度优化的正则表达式库(如PCRE)进行比较。

> 赢得基准测试游戏需要进行广泛的调优,大多数基准测试的Go版本需要关注。如果你测量可比较的C和Go程序(reverse-complement是一个例子),你会发现这两种语言在原始性能上比这个套件所示的要接近得多。

> 尽管如此,还有改进的空间。编译器很好但可以更好,许多库需要进行重大的性能工作,垃圾收集器还不够快(即使它是快的,注意不生成不必要的垃圾可能会产生巨大的影响)。

以下是最近邮件列表中关于计算机基准测试游戏的更多详细信息。

Garbage collection and performance in gccgo (1)

Garbage collection and performance in gccgo (2)

重要的是要注意,计算机基准测试游戏只是一个游戏。有经验的性能测量和容量规划人员会仔细匹配相似的工作负载,而不是玩游戏。

英文:

In the next release of the Go FAQ, something similar to the following should appear.

> Performance
>
> Why does Go perform badly on benchmark
> X?
>
> One of Go's design goals is to
> approach the performance of C for
> comparable programs, yet on some
> benchmarks it does quite poorly,
> including several in test/bench. The
> slowest depend on libraries for which
> versions of comparable performance are
> not available in Go. For instance,
> pidigits depends on a multi-precision
> math package, and the C versions,
> unlike Go's, use GMP (which is written
> in optimized assembler). Benchmarks
> that depend on regular expressions
> (regex-dna, for instance) are
> essentially comparing Go's stopgap
> regexp package to mature, highly
> optimized regular expression libraries
> like PCRE.
>
> Benchmark games are won by extensive
> tuning and the Go versions of most of
> the benchmarks need attention. If you
> measure comparable C and Go programs
> (reverse-complement is one example),
> you'll see the two languages are much
> closer in raw performance than this
> suite would indicate.
>
> Still, there is room for improvement.
> The compilers are good but could be
> better, many libraries need major
> performance work, and the garbage
> collector isn't fast enough yet (even
> if it were, taking care not to
> generate unnecessary garbage can have
> a huge effect).

And here's some more details on The Computer Benchmarks Game from a recent mailing list thread.

Garbage collection and performance in gccgo (1)

Garbage collection and performance in gccgo (2)

It's important to note that the Computer Benchmarks Game is just a game. People with experience in performance measurement and capacity planning carefully match like with like over realistic and actual workloads; they don't play games.

答案3

得分: 35

我的答案可能没有其他人那么技术性,但我认为它仍然相关。当我决定开始学习Go时,我在计算机基准游戏中看到了相同的基准测试。但是,我真的认为所有这些合成基准测试在决定Go是否足够快的方面都是无意义的。

最近,我使用Tornado+TornadIO+ZMQ在Python中编写了一个消息服务器,而对于我的第一个Go项目,我决定用Go重写服务器。到目前为止,当我将服务器的功能与Python版本相同时,我的测试结果显示Go程序的速度提高了约4.7倍。请注意,我可能只在Go中编程了一周,而在Python中编程已经超过5年了。

随着他们继续改进Go,它只会变得更快,我认为真正重要的是它在实际应用中的性能,而不是微小的计算基准测试。对我来说,Go显然比我在Python中能够产生的更高效的程序。这是我对这个问题的看法。

英文:

My answer isn't quite as technical as everyone else's, but I think it's still relevant.
I saw the same benchmarks on the Computer Benchmarks Game when I decided to start learning Go. But I honestly think all these synthetic benchmarks are pointless in terms of deciding whether Go is fast enough for you.

I had written a message server in Python using Tornado+TornadIO+ZMQ recently, and for my first Go project I decided to rewrite the server in Go. So far, having gotten the server to the same functionality as the Python version, my tests are showing me about 4.7x speed increase in the Go program. Mind you, I have only been coding in Go for maybe a week, and I have been coding in Python for over 5 years.

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.

答案4

得分: 8

事情已经改变了。

我认为当前对你的问题的正确答案是质疑Go语言慢的观点。在你提问的时候,你的判断是合理的,但是Go语言在性能方面已经取得了很大的进展。现在,虽然它还不如C语言快,但从总体上来说,它绝对不是慢10倍。

计算机语言基准测试游戏

截至本文撰写时:

源码		秒	KB		gz		CPU		CPU负载

reverse-complement
1.167倍
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.21倍
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.45倍
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.64倍
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.72倍
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
2倍
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.27倍
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.40倍
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.19倍
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.16倍
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%
英文:

Things have changed.

I think the current correct answer to your question is to contest the notion that go is slow. At the time of your inquiry your judgement was justified, but go has since gained a lot of ground in terms of performance. Now, it's still not as fast as C, but is no where near being 10x slower, in a general sense.

Computer language benchmarks game

At the time of this writing:

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%

答案5

得分: 5

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

需要注意的是,在thread-ring基准测试中,Go比Java快16倍。在相同的场景中,Go的CSP几乎可以与C++相媲美,但使用的内存少了4倍。

Go语言的强大之处在于其并发模型,即通信顺序进程(CSP),由Tony Hoare在70年代指定,易于实现并适用于高并发需求。

英文:

Despite the not so good efficiency of Go about the CPU cycles usage, the Go concurrency model is much faster than the thread model in Java, for instance, and can be comparable to C++ thread model.

Note that in the thread-ring benchmark, Go was 16x faster than Java. In the same scenario Go CSP was almost comparable to C++, but using 4x less memory.

The great power of Go language is its concurrency model, Communicating Sequential Processes, CSP, specified by Tony Hoare in 70's, being simple to implement and fit for highly concurrent needs.

答案6

得分: 2

有两个基本原因使得Java比Go和C++更快,并且在许多情况下甚至比C更快:

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

2)垃圾回收(GC)。基于GC的内存分配几乎是免费的,与malloc相比。而且“释放”开销可以在整个运行时中分摊 - 通常在程序终止之前不需要收集所有垃圾。

有数百(数千?)非常有才华的开发人员致力于使GC/JVM高效。认为自己“比他们都写得更好”是愚蠢的。这本质上是人类自我问题 - 人类很难接受,经过有才华的人适当培训后,计算机的性能将超过编程它的人。

顺便说一句,如果不使用任何面向对象的特性,C++可以和C一样快,但这时你几乎就等于直接用C编程了。

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

最后要注意的是,人们将“计算机语言基准测试游戏”称为“科学度量”。这些测试是完全有缺陷的。例如,如果你查看Java的nbody测试。当我在相同的操作系统/硬件上运行测试时,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在内存使用和墙上时间方面表现最好。

英文:

There are two basic reasons that that Java is faster than Go and C++, and can be faster than C in many cases:

  1. The JIT compiler. It can inline virtual function calls through multiple levels, even with OO classes, based on the runtime profile. This is not possible in a statically compiled language (although the newer re-compilation based on recorded profile can help). This is very important to most benchmarks that involve repetitive algorithms.

  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.

Btw, C++ can be as fast as C if you don't use and of the OO features, but then you are pretty close to just programming in C to begin with.

Most importantly, the "speed differences" in these tests are usually meaningless. The IO costs are orders of magnitude more than the performance differences, and so proper designs that minimize IO costs always win - even in a interpreted language. Very few systems are CPU bound.

As a final note, people refer to the "computer language benchmarks game" as a "scientific measure". The tests are completely flawed, For example, if you view the Java tests for nbody. When I run the tests on the same OS/hardware, I get roughly 7.6 secs for Java, and 4.7 secs for C - which is reasonable - not the 4x slowness the tests reports. It is click-bait, fake news, designed to generate site traffic.

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.

For a real world comparison of Java, Go, and C++ see https://www.biorxiv.org/content/10.1101/558056v1 spoiler alert, Java comes out on top in raw performance, with Go coming out on top with combined memory use and wall time.

答案7

得分: 1

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

英文:

I think an often overlooked fact is, that JIT compilation can be > static compilation especially for (runtime) late bound functions or methods. The hotspot JIT decides at RUNTIME which methods to inline, it even might adjust data layout to the cache size/architecture of the CPU it is currently running on.
C/C++ in general can make up (and overall will still perform better) by having direct access to the hardware. For Go things might look different as its more high-level compared to C, but currently lacks a runtime optimization system/compiler.
My gut tells me, Go could be faster then Java as Go does not enforce pointer chasing that much and encourages better data structure locality + requires less allocation.

答案8

得分: 1

事实上,Go语言不仅在设计时优雅高效,而且在运行时也非常高性能。关键是使用正确的操作系统,即LINUX。在Windows和Mac OS下的性能分析结果,可以说是相差一个或两个数量级。

英文:

As a matter of fact, Go is not only elegant and efficient at design time, but also super performant at run-time. The key is to use the right operating system i.e. LINUX. Performance profiling result under Windows and Mac OS are, for lack of a better word, one or two orders of magnitude inferior.

答案9

得分: 0

在Linux下,Go运行时非常快,与C/C++完全可比。而在Windows和Unix下的Go运行时则不在同一水平。

与Java的比较并不那么重要,Go既适用于系统开发,也适用于应用程序开发(而Java更像是专门用于应用程序开发的工具)。不详细讨论,但当像Kubernetes这样的项目使用Go编写时,你会意识到它并不是一个适合企业顾问的玩具。

我不记得谷歌曾经提到过你所提到的妥协。Go经过良好设计,简洁、优雅、高效,适用于设计系统和应用程序级别的程序,具有指针、高效的内存分配和释放,避免了由于实现继承容易被误用而导致的复杂性,提供了协程和其他现代化的编写高性能应用程序的方式,而且在Linux下非常快速,这正是它的设计初衷(非常高兴它能做到这一点)。

英文:

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

comparison with java is not so important, go is for both system and application development (as java is more like blue collar for application development only). will not enter in details, but when things like kubernetes are written in go, you realize that is not an enterprise consultant friendly toy

i do not remember google mentioning even once about the compromise you refer to. go is well design, simple, elegant and efficient for for designing system and application level programs, has pointers, efficient memory allocation and deallocation, avoids complications arising from oh so easy to miss-use implementation inheritance, giving you co-routines and other modern ways to write high performance applications in time and budget. again, go is super fast under linux, which is exactly what it was designed for (very happy that it does)

答案10

得分: -4

Java和C在数据和方法(函数)定义方面更加明确。C是静态类型的,而Java在继承模型方面则较为灵活。这意味着数据的处理方式在编译期间基本上已经确定。

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

请记住,谷歌对Go语言的目标是在执行速度和编码速度之间达到可接受的折中。我认为他们在早期尝试中找到了一个很好的平衡点,随着更多的工作完成,情况只会变得更好。

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

无论如何,更好的问题是,Go在编程易用性和执行速度之间是否达到了良好的折中?我的答案是肯定的,并且它应该会变得更好。

英文:

Both Java and C are more explicit with their data and method (function) definitions. C is statically typed, and Java is less so with its inheritance model. This means that the way the data will be handled is pretty much defined during the compilation.

Go is more implicit with its data and function definitions. The built in functions are more general in nature, and the lack of a type hierarchy (like Java or C++) gives Go a speed disadvantage.

Keep in mind that Google's goal for the Go language is to have an acceptable compromise between speed of execution and speed of coding. I think they are hitting a good sweet spot on their early attempt, and things will only improve as more work is done.

If you compare Go with more dynamically typed languages whose main advantage is speed of coding, you will see the execution speed advantage of Go. Go is 8 times faster than perl, and 6 times faster than Ruby 1.9 and Python 3 on those benchmarks you used.

Anyway the better question to ask is Go a good compromise in ease of programming versus speed of execution? My answer being yes and it should get better.

huangapple
  • 本文由 发表于 2010年4月24日 20:16:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/2704417.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定