为什么Go很慢(与Java相比)?
正如我们从计算机语言基准游戏中可以看到的那样 :
- Go平均比C慢10倍
- Go比Java慢三倍?
这怎么可能,记住Go编译器生成本地代码执行?
Go不成熟的编译器? 或者Go语言有一些固有的问题?
编辑:
大多数答案都否定了Go语言的内在缓慢,声称这个问题存在于不成熟的编译器中。
因此,我已经做了一些自己的testing来计算斐波纳契数字 :迭代algorithm在Go(freebsd,6g)中以与C中same
速度运行(使用O3选项)。 慢的recursion运行在Go中,比在C中慢2 times
(使用-O3选项;使用-O0 – 相同)。 但是我还没有看到在基准游戏中的10倍跌幅。
6g和8g编译器没有特别优化,所以它们生成的代码并不是特别快。
它们被devise成自己运行速度快,生成的代码没问题(有一些优化)。 gccgo
使用GCC现有的优化通行证,并可能提供与C更有意义的比较,但gccgo尚未完成function。
基准数字几乎完全是关于执行的质量。 除了实现花费运行时支持的基准testing并不真正需要的语言function之外,他们没有大量的语言function。 在大多数编译语言中,一个足够聪明的编译器在理论上可以去掉那些不需要的东西,但是由于很less真正的语言用户会编写那些不使用这个特性的程序。 如果不将它们完全移除(例如,在JIT编译的Java中预测虚拟调用目标),就会变得棘手。
FWIW,当我看看它时(基本上是一个整数加法的循环),我用Go来做一个非常简单的testing,gccgo为gcc -O0
和gcc -O2
之间的范围的快速结束产生了代码。本质上并不慢,但编译器并没有做任何事情。 对于一个10分钟的语言来说,这并不奇怪。
在Go FAQ的下一个版本中,应该显示类似于以下内容的内容。
性能
为什么Go在基准X上performance糟糕?
Go的devise目标之一就是为可比较的程序提供C的性能,但是在一些基准testing中,它的性能还是相当差劲的,其中包括几个testing/testing。 在Go中,最不依赖于可比较性能版本的库。 例如,pidigits依赖于一个多精度的math软件包,C版本与Go不同,使用GMP(用优化的汇编器编写)。 基于正则expression式的基准testing(例如regex-dna)基本上将Go的stopgap regexp软件包与成熟的,高度优化的正则expression式库(比如PCRE)相比较。
基准游戏是通过广泛的调优赢得的,大多数基准的Go版本都需要关注。 如果您衡量可比较的C和Go程序(反向补充就是一个例子),您会看到这两种语言在原始性能上比这个套件所指示的更接近。
不过,还有改进的空间。 编译器是好的,但可能会更好,许多图书馆需要主要的性能工作,垃圾收集器还不够快(即使是,注意不要产生不必要的垃圾会产生巨大的影响)。
以下是最近邮件列表主题上“计算机基准游戏”的更多细节。
垃圾收集和gccgo性能(1)
垃圾收集和gccgo性能(2)
“计算机基准游戏”只是一个游戏,这一点很重要。 在性能测量和容量规划方面具有丰富经验的人员要像现实和实际的工作负载一样仔细匹配; 他们不玩游戏。
我的答案不像其他人那样技术性强,但是我认为这还是相关的。 当我决定开始学习Go时,我在计算机基准游戏中看到了相同的基准。 但是我真的认为,所有这些合成基准在决定Go是否足够快的方面都是毫无意义的。
我最近使用Tornado + TornadIO + ZMQ在Python中编写了一个消息服务器,对于我的第一个Go项目,我决定在Go中重写服务器。 到目前为止,获得服务器的function与Python版本相同,我的testing显示Go程序的速度增加了4.7倍。 请注意,我只用Go编写了一个星期的代码,而且我已经用Python编写了5年多了。
Go只是在继续工作的时候才会变得更快,我认为这归结于它在真实应用程序中的performance,而不是微小的计算基准。 对我来说,Go显然比我在Python中产生的效率更高。 这是我对这个问题的回答。
在几个基准testing的情况下,很容易指出导致速度放慢的特定运行时间或库差异。
二叉树基准被描述为“ testingGC的基准的改编 ”。 Go的GC目前不是Java或C#所在的地方,而且工作负载上有大量的包含指针的对象,并且显示出大量的内存压力。 如果这是一个实时Go应用程序中的问题,那么您将实现自己的对象池/空闲列表来重用此types的对象[编辑:使用Go的CloudFlare中的人员, 恰好发生了关于如何执行此操作的信息 ]。 一般来说,这是一种控制GC'd语言中使用的GC成本的方法,但正如链接页面所指出的那样,它被这个基准的规则排除在外。
pidigits基准testing使用了Go的大math库,比C的GMP或者Java的库要慢。 如果您的应用程序的性能受限于速度(可能是公钥密码和一些math/科学应用程序中的一个因素; Web应用程序后端中less一个),您可能想要从C库中调用去或者只是使用不同的语言。
正如接受的答案所说,许多其他的差异可能归结为代码生成不太好的代码。
当然,你想要以更广泛的视angular来做出select,而不仅仅是基准。 包括我在内的许多Go用户似乎都来自脚本语言 ,似乎喜欢types推断,并发工具和快速编译。 另一方面,生态系统的相对不成熟(与Java,C语言甚至Python相比)是一个很大的缺点,可能比基准数量要大。 无论如何,如果您有兴趣,似乎都值得一试。
尽pipeGo使用CPU周期的效率并不是很好,但是Go并发模型比Java中的线程模型快得多,并且可以与C ++线程模型相媲美。
看看在线程基准testing中 ,Go比Java快了16倍 。 在相同的情况下,Go CSP与C ++几乎相当,但是使用的内存减less了4倍。
Go语言的强大之处在于70年代托尼·霍尔(Tony Hoare)指定的并发模型 – 沟通顺序进程(CSP),它易于实现,适合于巨大的并发。
这一切都归结为编写代码需要多长时间,以及从开发的任何代码获得最佳性能所需的工作量。 其他的一切都只是一个书呆子的追求,没有太多的相关性在商业…….这样的事情。
围棋使开发伟大的服务更容易支持。 Java …不pipe它的技术能力…恶梦,以支持….
我写了一些Golang的程序……快速地通过一只鹅……如果我的任务是整天严肃认真地研究math……我不认为我会用Java或Go来做这件事。我会用这种语言来devise的。
我认为一个经常被忽视的事实是,JIT编译可以>静态编译,特别是(运行时)后期绑定函数或方法。 热点JIT在RUNTIME决定了哪些内联方法,甚至可以将数据布局调整为当前正在运行的CPU的caching大小/架构。 一般来说C / C ++可以通过直接访问硬件来弥补(总的来说还是会performance得更好)。 对于Go而言,与C相比,更高级的东西可能看起来不同,但是目前缺less运行时优化系统/编译器。 我的直觉告诉我,Go 可能比Java更快,因为Go没有强制执行指针,鼓励更好的数据结构局部性+需要更less的分配。
事情变了。
我认为你的问题目前正确的答案是争取走的速度缓慢的概念。 在你询问的时候,你的判断是合理的,但是从performance上来说,这已经获得了很多的理由。 现在,它的速度还不及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%
尽pipe如此,它在二叉树基准上遭受了惨痛的折磨:
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和C对数据和方法(函数)定义都更加明确。 C是静态types的,而Java的inheritance模型就不那么简单了。 这意味着在编译过程中数据的处理方式非常多。
Go更隐含其数据和函数定义。 内置的函数本质上是更通用的,缺lesstypes层次结构(如Java或C ++)给Go带来了速度上的缺点。
请记住,Google Go语言的目标是在执行速度和编码速度之间达成可接受的折中。 我认为他们在早期的尝试中是一个不错的select,而且随着更多的工作完成,情况才会有所改善。
如果您将Go与更多的dynamictypes语言(主要优势在于编码速度)进行比较,您将看到Go的执行速度优势。 Go比perl快了8倍,比使用这些基准的Ruby 1.9和Python 3快了6倍。
无论如何,要问的更好的问题是在编程和执行速度之间做出一个很好的妥协? 我的回答是肯定的,它应该会变得更好。