【发布时间】:2012-08-29 17:47:00
【问题描述】:
谁能解释为什么下面的递归方法比迭代方法快(两者都在做字符串连接)?迭代方法不是要打败递归方法吗?再加上每个递归调用都会在堆栈顶部添加一个新层,这可能会非常低效。
private static void string_concat(StringBuilder sb, int count){
if(count >= 9999) return;
string_concat(sb.append(count), count+1);
}
public static void main(String [] arg){
long s = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < 9999; i++){
sb.append(i);
}
System.out.println(System.currentTimeMillis()-s);
s = System.currentTimeMillis();
string_concat(new StringBuilder(),0);
System.out.println(System.currentTimeMillis()-s);
}
我多次运行程序,递归的总是比迭代的快 3-4 倍。导致迭代速度变慢的主要原因可能是什么?
【问题讨论】:
-
确保你学会了如何正确地进行微基准测试。您应该为这两者的多次迭代计时并为您的时间平均这些迭代。除此之外,您应该确保 VM 不会通过不编译第一个来给第二个带来不公平的优势。
-
另外,改变它们的顺序,在一个循环中重复整个测试至少五次(放弃前两次进行预热)并使用 System.nanoTime
-
事实上,默认的 HotSpot 编译阈值(可通过
-XX:CompileThreshold配置)是 10,000 次调用,这可能解释了您在此处看到的结果。 HotSpot 并没有真正做任何尾部优化,所以递归解决方案更快是很奇怪的。 -
尝试颠倒递归方法和迭代方法的位置。你会看到你观察的反面:)
-
您的递归方法更快只是因为当您运行迭代方法时 JVM 尚未预热。