首页 > 解决方案 > 在JAVA的嵌套for循环中,为什​​么小循环中的大循环比大循环中的小循环更快?

问题描述

当迭代次数相同时,我想知道外部“for循环”的较小迭代是否更快。

这是我的java代码。

总循环迭代次数为 1000 亿次。

public class Test {

    public static long run1() {
        final long start = System.nanoTime();
        long cnt = 0;
        for(int i = 0; i<1000000000; i++) {
            for(int j = 0 ; j<100 ; j++) {
                cnt++;
            }
        }
        final long end = System.nanoTime();

        System.out.println("run1 : "+(end-start)*1e-9+" sec");
        return start - end;
    }



    public static long run2() {
        final long start = System.nanoTime();
        long cnt = 0;
        for(int i = 0; i<100; i++) {
            for(int j = 0 ; j<1000000000 ; j++) {
                cnt++;
            }
        }
        final long end = System.nanoTime();

        System.out.println("run2 : "+(end-start)*1e-9+" sec");
        return start - end;
    }


    public static void main(String[] args) {

        for(int i = 0 ; i < 10 ; i++) {
            long test1 = run1();
            long test2 = run2();
            System.out.println("Time diff : "+(test1-test2)*1e-9+" sec\n");
        }
    }
}

这是结果

run1 : 4.5772473950000006 sec
run2 : 1.7155700900000002 sec
Time diff : -2.861677305 sec

run1 : 4.4107229420000005 sec
run2 : 1.6532413140000002 sec
Time diff : -2.7574816280000003 sec

run1 : 3.815836296 sec
run2 : 1.761153921 sec
Time diff : -2.054682375 sec

run1 : 3.913543021 sec
run2 : 1.752971717 sec
Time diff : -2.1605713040000003 sec

run1 : 3.851766485 sec
run2 : 1.7262416440000001 sec
Time diff : -2.1255248410000003 sec

run1 : 3.95305219 sec
run2 : 1.7323067330000002 sec
Time diff : -2.220745457 sec

run1 : 3.924869236 sec
run2 : 1.6953032440000002 sec
Time diff : -2.229565992 sec

run1 : 3.839871705 sec
run2 : 1.692300162 sec
Time diff : -2.147571543 sec

run1 : 3.93864626 sec
run2 : 1.704322469 sec
Time diff : -2.234323791 sec

run1 : 3.863758493 sec
run2 : 1.700392962 sec
Time diff : -2.163365531 sec

像这样,

我想知道为什么会出现这些结果。

并且,通过三重嵌套循环编辑,获得了类似的结果。

标签: javaperformancefor-loopnested

解决方案


简短的回答是:JIT 和你的数学是错误的。

让我们从你的运行方法开始,它以这个打印行和一个返回结束

System.out.println("run1 : "+(end-start)*1e-9+" sec");
return start - end;

这里的问题是您正在打印 end-start 并返回 start-end。我没有在运行方法中进行数学运算,而是将其转移,以便每次运行只负责运行和计时:

public class loops
{

  public static long run1()
  {
    final long start = System.nanoTime();
    long cnt = 0;
    for (int i = 0; i < 1000000000; i++)
    {
      for (int j = 0; j < 100; j++)
      {
        cnt++;
      }
    }
    final long end = System.nanoTime();
    return end - start;
  }

  public static long run2()
  {
    final long start = System.nanoTime();
    long cnt = 0;
    for (int i = 0; i < 100; i++)
    {
      for (int j = 0; j < 1000000000; j++)
      {
        cnt++;
      }
    }
    final long end = System.nanoTime();
    return end - start;
  }

  public static void main(String[] args)
  {

    for (int i = 0; i < 10; i++)
    {
      long test1 = run1();
      long test2 = run2();
      System.out.println("run1 : " + test1 + " ns");
      System.out.println("run2 : " + test2 + " ns");
      System.out.println("Time diff : " + (test1 - test2) + " ns\n");
    }
  }
}

我还拿出了数学,因为……好吧,何必呢?将值视为纳秒有什么问题?原来是这样的...

运行此程序,您可以看到初始大值减小并接近零。在某些运行中,两个版本的它们甚至都达到零。

Java 8 运行

零纳秒?是的,即时计算。让量子计算吸吮它!好吧,这不是即时的。不是当您检查nanoTime 描述时:

此方法提供纳秒精度,但不一定提供纳秒分辨率(即值变化的频率)

它只是比可测量的要快,因为 JIT 可能最终发现该方法实际上并没有做任何事情。现在为什么一个或另一个比另一个下降得更快需要更深入地研究 JIT 以及它如何决定优化一种方法与另一种方法 - 这比我知道的要多。

最终,几乎没有区别。两种方法初次运行后,最大的时间差最多只有几毫秒。我不认为说一个版本真的比另一个版本快有什么意义。

有趣的旁注:JDK-11 似乎表现不佳...... Java 11 运行

GraalVM 似乎表现不佳......虽然,可能有一些标志可以改善它...... 虚拟机


推荐阅读