为什么GoLang解决scheme比同等的Java解决scheme更快?

最近在工作中,我们玩弄了IBM提出的以下测验问题https://www.research.ibm.com/haifa/ponderthis/challenges/May2015.html

经过一番努力,一位同事和我已经到了两个解决scheme,一个在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版本在MacOS Sierra 10.12.3上运行的,后者在2013年末的视网膜MacBook Pro上搭配2.6GHz i5 CPU。

为什么Go程序比Java程序快5倍,当大多数基准testing都表明Java应该运行在同一个运行时? 这只是一个循环中的基本math,所以它似乎应该在同一时间运行。 对于JVM的启动时间,我可以理解大概一秒左右,但是这似乎没有关系。

两个程序几乎都使用相同的循环。 游戏结果的所有可能的排列被创build并迭代每个开始的金额。 看起来,对于围绕Java运行的Go循环中的任何循环操作而言,似乎都是如此。

我知道这是一个“微观”基准testing,但是我想知道为什么Go代码大大优于Java代码。 只是简单的循环/math是更有效的,因此更快? 它能否展开循环(虽然这似乎不太可能产生如此巨大的差异)?

如果不是,你应该如何构build一个Java程序来获得最简单的循环和math运算的性能?

编辑 – 感谢Dolda2000我已经修改了Java版本。 现在和GoLang版本的速度差不多。 事实上,问题在于游戏的创build导致Java版本必须模拟更多游戏来确定游戏是否足够长。 随着这些变化,现在运行了大约6秒钟,并恢复了我对Java的信心。

更新 – 这是一个扩展的文章 ,进一步详细讨论了这个问题的背景。

事实certificate,你的程序并不像你所相信的那样平等。 我安排他们看看他们模拟的有多less场比赛(也就是单独的下注回合),而当Go版本模拟1 612 629 805游戏时,Java版本模拟了12 323 903 502场比赛,差不多要多一个数量级。

在我的机器上,closuresmultithreading以获得更可预测的结果,Java程序在75秒钟左右,而Go程序在12.5秒钟。 与整个运行时间相比,看起来,每个模拟游戏的Java程序实际上稍微快了 6.1ns,而Go程序只有7.8ns。

不过还不确定为什么他们模拟了这么多不同数量的游戏。 也许Go版本生成回合的方式只是发现更快的终止。

编辑 :其实,最后的猜测使很多的意义。 Go的版本是通过调整游戏的最初轮次来开始的,而Java版本则是通过调整游戏的最后一轮来开始的(换句话说,将轮次列表看作是增加的11位基数的列表3数字,Go版本是小端的,而Java版本是大端的,所以Java版本将不得不通过更多相同的开始来模拟终止的变化。 我没有试图去validation这个假设,但是我确信我不需要。