java迭代和 递归的异同_Java迭代与递归

任何人都可以解释为什么下面的递归方法比迭代方法更快(两者都在进行字符串连接)?是不是迭代的方法想要打败递归的?加上每个递归调用在堆栈顶部添加一个新层,这可能是非常低效的空间.

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倍.可能导致迭代速度变慢的主要原因是什么?

解决方法:

Make sure you learn how to properly microbenchmark. You should be timing many iterations of both and averaging these for your times. Aside from that, you should make sure the VM isn’t giving the second an unfair advantage by not compiling the first.

In fact, the default HotSpot compilation threshold (configurable via -XX:CompileThreshold) is 10,000 invokes, which might explain the results you see here. HotSpot doesn’t really do any tail optimizations so it’s quite strange that the recursive solution is faster. It’s quite plausible that StringBuilder.append is compiled to native code primarily for the recursive solution.

我决定改写基准测试并亲自查看结果.

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);

}

}

这是我的结果……

06001

这些是平均超过1000次试验的每种方法的时间.

从本质上讲,您的基准测试的问题在于它不是多次试验的平均值(law of large numbers),并且它高度依赖于各个基准的排序.我给你的最初结果是:

06002

这对我来说没什么意义. HotSpot VM上的递归很可能不会像迭代那样快,因为它还没有实现您可能用于函数式语言的任何类型的尾部优化.

现在,这里发生的有趣的事情是默认的HotSpot JIT编译阈值是10,000次调用.在编译追加之前,您的迭代基准测试很可能会在大多数情况下执行.另一方面,您的递归方法应该相对较快,因为它很可能在编译后享受追加.为了消除这影响结果,我通过-XX:CompileThreshold = 0并找到…

06003

所以,当它归结为它时,它们的速度大致相等.但请注意,如果平均值具有更高的精度,则迭代似乎会更快一些.订单可能仍会对我的基准测试产生影响,因为后者的基准测试将具有VM为其动态优化收集更多统计信息的优势.

标签:java,recursion

来源: https://codeday.me/bug/20190725/1537518.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值