2015-10-26 76 views
2

當我檢查這Question不能相信它,所以我測試,似乎是真實的。循環內的聲明似乎比聲明外部循環更快。有人能解釋這是爲什麼嗎?爲什麼在循環內聲明似乎比在Java中聲明外部循環更快?

這裏是我的測試代碼:

public class CycleTest { 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     long iterations = 1000000; 
     warmUp(iterations); 
     System.out.println("Cycle1"); 
     double individualTime = getAverageTimePerIterationc1(iterations); 
     iterations = 1000; 
     double totalTime = getTotalTimec1(iterations); 

     System.out.println("ns/iteration: " + individualTime); 
     System.out.println("Total time for " + iterations + " runs: " + totalTime); 

     System.out.println("Cycle2"); 
     iterations = 1000000; 
     double individualTime1 = getAverageTimePerIterationc2(iterations); 
     iterations = 1000; 
     double totalTime1 = getTotalTimec2(iterations); 

     System.out.println("ns/iteration: " + individualTime1); 
     System.out.println("Total time for " + iterations + " runs: " + totalTime1); 

    } 

    public static void warmUp(long iterations) { 
     System.out.println("Starting warmup"); 
     for (int i = 0; i < iterations; i++) { 
      runCycles(); 
      runCycles1(); 
     } 
    } 

    public static double getAverageTimePerIterationc1(long iterations) { 
     // test 
     System.out.println("Starting individual time test"); 
     long timeTaken = 0; 
     for (int i = 0; i < iterations; i++) { 
      long startTime = System.nanoTime(); 
      runCycles(); 
      timeTaken += System.nanoTime() - startTime; 
     } 
     return (double) timeTaken/iterations; 
    } 

    public static long getTotalTimec1(long iterations) { 
     // test 
     System.out.println("Starting total time test"); 
     long timeTaken = 0; 
     for (int i = 0; i < iterations; i++) { 
      long startTime = System.nanoTime(); 
      runCycles(); 
      timeTaken += System.nanoTime() - startTime; 
     } 
     return timeTaken; 
    } 

    public static double getAverageTimePerIterationc2(long iterations) { 
     // test 
     System.out.println("Starting individual time test"); 
     long timeTaken = 0; 
     for (int i = 0; i < iterations; i++) { 
      long startTime = System.nanoTime(); 
      runCycles1(); 
      timeTaken += System.nanoTime() - startTime; 
     } 
     return (double) timeTaken/iterations; 
    } 

    public static long getTotalTimec2(long iterations) { 
     // test 
     System.out.println("Starting total time test"); 
     long timeTaken = 0; 
     for (int i = 0; i < iterations; i++) { 
      long startTime = System.nanoTime(); 
      runCycles1(); 
      timeTaken += System.nanoTime() - startTime; 
     } 
     return timeTaken; 
    } 

    private static void runCycles() { 
     double intermediateResult; 
     for (int i = 0; i < 1000; i++) { 
      intermediateResult = i; 
      intermediateResult += 1; 
     } 
    } 

    private static void runCycles1() { 
     for (int i = 0; i < 1000; i++) { 
      double intermediateResult = i; 
      intermediateResult += 1; 
     } 
    } 
} 

附加新的信息:我有一個Windows機器上JDK 1.6.0_27運行它。

+0

行'System.out.println(intermediateResult);'當你做測試時註釋掉了嗎? –

+2

該代碼看起來非常熟悉;)http://codereview.stackexchange.com/a/108562/87743 – Zymus

+0

@Paul Boddington是的,它是爲了避免超出輸出。 –

回答

5

它們生成相同的代碼。這兩種方法:

private static void runCycles1() { 
    double intermediateResult; 
    for (int i = 0; i < 1000; i++) { 
     intermediateResult = i; 
    } 
} 
private static void runCycles2() { 
    for (int i = 0; i < 1000; i++) { 
     double intermediateResult = i; 
    } 
} 

生成Java中這8字節碼(jdk1.8.0_51):

runCycles1()    runCycles2() 
Code:      Code: 
    0: iconst_0     0: iconst_0    i = 0 
    1: istore_2     1: istore_0 
    2: goto   11   2: goto   11  goto 11 

    5: iload_2     5: iload_0     intermediateResult = (double)i 
    6: i2d      6: i2d 
    7: dstore_0     7: dstore_1 
    8: iinc   2, 1  8: iinc   0, 1  i++ 

    11: iload_2     11: iload_0     if (i < 1000) goto 5 
    12: sipush  1000  12: sipush  1000 
    15: if_icmplt  5   15: if_icmplt  5 
    18: return     18: return     return 

實際的聲明不產生任何代碼,所以如果你看到我會感到驚訝性能上的差異。

所以測試了它:

for (int j = 0; j < 10; j++) { 
    long t1 = System.nanoTime(); 
    for (int i = 0; i < 1000_000_000; i++) 
     runCycles1(); 
    long t2 = System.nanoTime(); 
    for (int i = 0; i < 1000_000_000; i++) 
     runCycles2(); 
    long t3 = System.nanoTime(); 
    System.out.printf("%d %d%n", t2 - t1, t3 - t2); 
} 

,並得到:

4250095 2020120 
4067898 0 
3904236 0 
0 0 
0 0 
0 0 
0 0 
0 0 
0 0 
0 0 

他們都最終編譯不了了之!

+0

代碼中加入'intermediateResult + = 1;'。我希望這可以產生不同的字節碼。 –