为什么这个GoLang解决方案比同等的Java解决方案更快?

时间:2017-03-29 00:17:34

标签: java performance go

最近在工作中,我们正在讨论IBM https://www.research.ibm.com/haifa/ponderthis/challenges/May2015.html

提出的以下测验问题

经过一番努力,一位同事和我已经达成了两个解决方案,一个是GoLang https://gist.github.com/walesey/e2427c28a859c4f7bc920c9af2858492#file-main-go-L57,另一个是Java https://gist.github.com/boyter/42df7f203c0932e37980f7974c017ec5#file-puzzle-java-L63,它们具有性能关键的方法,可以在Java和游戏中使用PlayGames GoLang(两者都在上面链接)。

Go程序几乎是Java程序的文字副本,但其运行时间约为6秒,而Java程序约为26秒(在我的本地计算机上)。类似的数字被复制到其他一些机器上,Go程序的速度提高约5倍。

Go程序使用1.7.5和Java编译,使用版本1.8.0_65,在2013年末的视网膜Macbook Pro和2.6GHz i5 CPU上的macOS Sierra 10.12.3上运行。

为什么Go程序比Java程序快5倍,因为大多数基准测试表明Java应该在同一个运行时?它只是一个循环中的基本数学,所以看起来它们应该在大约相同的时间运行。我可以理解JVM启动时间大约一秒钟,但这似乎关闭了。

两个程序都使用几乎相同的循环。对于每个起始金额,创建并迭代所有可能的游戏结果排列。看来,对于主循环中的任意数量的循环操作,Go在Java周围运行环。

我知道这是一个" micro"基准测试,但我想知道为什么Go代码大大优于Java代码。 Go for simple循环/数学是否更有效,因此更快?它是否能够展开循环(虽然这似乎不太可能产生如此巨大的差异)?

如果不是,您应该如何构建Java程序以从简单的循环和数学运算中获得最佳性能?

编辑 - 感谢Dolda2000,我修改了Java版本。它现在与GoLang版本大致相同。事实上,问题在于游戏的创建导致Java版本必须模拟更多游戏以确定游戏是否足够长。随着变化,它现在运行大约6秒钟,并恢复了我对Java的信心。

更新 - 这是一个expanded essay,会更详细地讨论这个问题的背景。

1 个答案:

答案 0 :(得分:47)

事实证明,你的节目并不像你认为的那样平等。我指导他们看看他们模拟了多少场比赛(也就是个人投注轮次),而Go版本模拟了1 612 629 805场比赛,Java版本模拟了12 323 903 502场比赛,几乎要高出一个数量级。

在我的机器上,关闭多线程以获得更可预测的结果,Java程序在大约75秒内启动,Go程序在12.5秒内启动。与整个运行时匹配,似乎Java程序实际上每个模拟游戏的更快,大约为6.1 ns,而Go程序为7.8 ns。

不确定为什么他们会模拟这么多不同数量的游戏。也许Go版本生成回合的方式恰好可以找到更快的终止。

编辑:实际上,最后一次猜测很有意义。 Go版本通过调整游戏的初始轮次开始,而Java版本则通过调整游戏的最后几轮开始(换句话说,将轮次列表视为增加的11位数基数列表-3数字,Go版本是little-endian,而Java版本是big-endian,可以这么说),因此Java版本必须通过更多相同的开始来模拟终止的变体。我没有试图验证这个假设,但我确信我认为不需要这样做。