私のコメントを参照してください。
マイクロベンチマークを適切に行う方法を必ず学んでください。あなたは両方の多くの反復のタイミングをとり、あなたの時間のためにこれらを平均するべきです。それとは別に、最初のコンパイルを行わないことで、VMが2番目の利点を不当に与えていないことを確認する必要があります。
実際、デフォルトのHotSpotコンパイルしきい値(を介して構成可能-XX:CompileThreshold
)は10,000回の呼び出しであり、ここに表示される結果を説明している可能性があります。HotSpotは実際にはテールの最適化を行わないため、再帰的なソリューションの方が高速であるのは非常に奇妙です。StringBuilder.append
主に再帰的ソリューションのためにネイティブコードにコンパイルされることは非常に妥当です。
ベンチマークを書き直して、自分で結果を確認することにしました。
public final class AppendMicrobenchmark {
static void recursive(final StringBuilder builder, final int n) {
if (n > 0) {
recursive(builder.append(n), n - 1);
}
}
static void iterative(final StringBuilder builder) {
for (int i = 10000; i >= 0; --i) {
builder.append(i);
}
}
public static void main(final String[] argv) {
/* warm-up */
for (int i = 200000; i >= 0; --i) {
new StringBuilder().append(i);
}
/* recursive benchmark */
long start = System.nanoTime();
for (int i = 1000; i >= 0; --i) {
recursive(new StringBuilder(), 10000);
}
System.out.printf("recursive: %.2fus\n", (System.nanoTime() - start) / 1000000D);
/* iterative benchmark */
start = System.nanoTime();
for (int i = 1000; i >= 0; --i) {
iterative(new StringBuilder());
}
System.out.printf("iterative: %.2fus\n", (System.nanoTime() - start) / 1000000D);
}
}
これが私の結果です...
C:\dev\scrap>java AppendMicrobenchmark
recursive: 405.41us
iterative: 313.20us
C:\dev\scrap>java -server AppendMicrobenchmark
recursive: 397.43us
iterative: 312.14us
これらは、1000回の試行で平均した各アプローチの時間です。
基本的に、ベンチマークの問題は、多くの試行(大数の法則)で平均化されないことと、個々のベンチマークの順序に大きく依存することです。私があなたのために与えた元の結果:
C:\dev\scrap>java StringBuilderBenchmark
80
41
これは私にはほとんど意味がありませんでした。HotSpot VMでの再帰は、関数型言語で使用されるようなテール最適化をまだ実装していないため、反復ほど高速ではない可能性があります。
ここで発生する面白いことは、デフォルトのHotSpotJITコンパイルしきい値が10,000回の呼び出しであるということです。反復ベンチマークは、コンパイルされる前にほとんどの部分で実行される可能性が高くなります。 append
一方、再帰的アプローチは、コンパイルappend
後に楽しむ可能性が高いため、比較的高速である必要があります。これが結果に影響を与えないようにするために、私は合格-XX:CompileThreshold=0
して見つけました...
C:\dev\scrap>java -XX:CompileThreshold=0 StringBuilderBenchmark
8
8
つまり、どちらも速度はほぼ同じです。ただし、より高い精度で平均化すると、反復が少し速くなるように見えることに注意してください。後者のベンチマークには、動的最適化のためにより多くの統計を収集したVMの利点があるため、順序によってベンチマークにも違いが生じる可能性があります。