嵌套循环的效率

时间:2010-03-31 06:06:04

标签: nested-loops

请参阅以下代码段:

    Long first_begin = System.currentTimeMillis();

    // first nested loops
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 1000000; j++) {
            // do some stuff
        }
    }
    System.out.println(System.currentTimeMillis() - first_begin);
    // second nested loops
    Long seconde_begin = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        for (int j = 0; j < 10; j++) {
            // do some stuff
        }
    }
    System.out.println(System.currentTimeMillis() - seconde_begin);

我想知道为什么第一个嵌套循环的运行速度比第二个慢?

问候!

重要提示!:很抱歉,当我第一次提出这个问题时,我意外地将变量j从1开始,我已经进行了修正。

更新:循环中没有任何特定的逻辑,我只是​​做一些测试,实际上这是一个在面试中提出的问题,面试官提示我改变循环的顺序以获得更好的性能。顺便说一句,我使用的是JDK1.5。经过一些测试我现在比较困惑,因为程序的结果不一致---有时候第一个循环比第二个循环运行得快,但大部分时间它的运行速度比第二个慢。

4 个答案:

答案 0 :(得分:6)

编辑:原始答案如下。现在您已经修复了示例以便所有循环变量从0开始,我们又回到了没有足够的信息。似乎可能它是参考问题的缓存一致性/局部性 - 但我们只是在猜测。如果你能提供一个简短而完整的程序来证明这个问题,那将会有所帮助......就像告诉我们我们正在谈论的语言/平台一样!


第一个循环有10 * 999999 = 9999990次迭代。第二个循环具有1000000 * 9 = 9000000次迭代。因此,我希望期望(所有其他条件相同)第一个循环需要更长的时间。

但是,您还没有说明您正在做什么工作或者这是什么平台。有很多事情可能会影响事情:

  • 第二个循环可能会更好地点击缓存
  • 如果您使用的是JIT编译平台,JIT可能会选择更严格地优化第二个循环。
  • 您正在执行的操作本身可能有缓存或类似的内容
  • 如果您正在执行少量工作,但它首先需要加载并初始化一堆类型,这可能会导致第一个循环变慢

答案 1 :(得分:4)

这个答案是针对更新的问题:

  • 如果您正在访问int[][]等二维数组,则内循环中值较大的数组应该较慢。不是很多,但仍然。要稍微了解这个问题,请阅读Joel博客文章中的Shlemiel the street painter
  • 您获得不一致结果的原因是您没有执行任何JVM预热。 JVM不断分析运行的字节码并对其进行优化,通常只有在30到50次迭代后才能以最佳速度运行。是的,这意味着您需要首先运行代码几十次,然后从平均另外几十次运行中对其进行基准测试,因为垃圾收集器会减慢运行速度。
  • 一般说明,使用Long对象而不是long原语只是愚蠢的,JVM很可能通过用原始代替它来优化它,如果它可以,如果它不能,则必然会是一些(虽然非常轻微)使用它不断减速。

答案 2 :(得分:2)

问题转移了。这些不是你寻求的机器人......

因为你在第一个例子中做了大约100万次的工作。 ; - )

答案 3 :(得分:2)

如果查看生成的字节代码,两个循环几乎相同。除了它为10循环执行while条件之外,Java从指令中获取10作为立即值,但是当它为1000000循环执行while条件时,Java从变量中加载1000000。我没有关于执行每条指令需要多长时间的任何信息,但似乎立即加载比变量加载更快。

请注意,在第一个循环中,与1000000的比较必须进行1000万次,而在第二个循环中,它只进行了100万次。当然,在第二个循环中,与10的比较更为常见,但如果变量负载比立即负载慢得多,那么这将解释您所看到的结果。