最近仕事で、IBMが尋ねた次のクイズの質問をいじっていました https://www.research.ibm.com/haifa/ponderthis/challenges/May2015.html
少しの努力の後、同僚と私は2つのソリューションに到達しました。1つはGoLangにあります https://Gist.github.com/walesey/e2427c28a859c4f7bc920c9af2858492#file-main-go-L57 とJava https://Gist.github.com/boyter/42df7f203c0932e37980f7974c017ec5#file-puzzle-Java-L6 JavaとGoLangのゲーム(両方とも上記にリンク)。
GoプログラムはほとんどJavaのリテラルコピーですが、ランタイムは約6秒ですが、Javaの場合は約26秒です(ローカルマシン上)。他のいくつかのマシンでも同様の数値が複製され、Goプログラムは約5倍高速になりました。
Goプログラムは、バージョン1.8.0_65を使用して1.7.5およびJavaを使用してコンパイルされます。両方とも、2.6GHz i5 CPUを搭載した2013年後半のRetina Macbook ProのmacOS Sierra 10.12.3で実行されます。
ほとんどのベンチマークでJavaがほぼ同じランタイムであることが示されているのに、GoプログラムがJavaの5倍速いのはなぜですか?ループ内の基本的な数学なので、ほぼ同じ時間に実行する必要があるようです。 JVMの起動時間は1秒程度理解できましたが、これはうまくいかないようです。
両方のプログラムは、ほぼ同じループを使用します。ゲーム結果の可能な順列はすべて作成され、開始金額ごとに繰り返されます。メインループ内の任意の数のループ操作について、GoがJavaの周りでリングを実行しているようです。
これは「マイクロ」ベンチマークであることは理解していますが、GoコードがJavaコードよりもはるかに優れているのはなぜだろうと思っています。単純なループ/数学のGoの方が効率的であり、したがって高速であるというだけですか?おそらくループを展開することはできますか?(これはそのような大きな違いを生む可能性は低いようですが)
そうでない場合は、Javaプログラムをどのように構成して、単純なループと数学演算から最高のパフォーマンスを引き出す必要がありますか?
[〜#〜] edit [〜#〜]-Dolda2000のおかげで、Javaバージョンを変更しました。現在、GoLangバージョンとほぼ同じ速度です。確かに問題は、ゲームが作成されたため、Javaバージョンがゲームを十分に長くしたかどうかを判断するためにより多くのゲームをシミュレートする必要があったことです。変更により、約6秒で実行され、Javaへの信頼が回復しました。
Update-ここに 拡張されたエッセイ があり、この質問の背景をさらに詳しく説明しています。
結局のところ、あなたのプログラムはあなたが信じているほど平等ではありません。シミュレートしたゲームの数(つまり、個々のベットラウンド)を確認するためにインストルメントを作成しました。Goバージョンは1 612 629 805ゲームをシミュレートし、Javaバージョンは12 323 903 502ゲームをシミュレートしました。ほぼ一桁以上。
私のマシンでは、より予測可能な結果を得るためにマルチスレッドをオフにし、Javaプログラムは約75秒で記録され、Goプログラムは12.5秒で記録されます。 Javaプログラムは、Goの7.8 nsと比較して、シミュレーションされたゲームごとに実際にはわずかより速い、約6.1 ns)プログラム。
しかし、なぜ非常に異なるゲーム数をシミュレートするのかはまだわかりません。おそらく、Goバージョンがラウンドを生成する方法は、より多くのより迅速な終了を見つけるために起こります。
[〜#〜] edit [〜#〜]:実際、最後の推測は非常に理にかなっています。 Goバージョンは、ゲームの最初のラウンドを調整することから始まりますが、Javaバージョンは、ゲームの最後のラウンドを調整することから始まります(言い換えれば、ラウンドのリストを増加する11桁の基数3のリスト、Goバージョンはリトルエンディアン、Javaバージョンはいわばビッグエンディアンです)、Javaバージョンは、終了するバリエーションに到達するために、より多くの同一の開始点を介してシミュレートする必要があります。この仮説を検証しようとしませんでしたが、その必要性を感じないほど十分です。