2014-02-14 112 views
0

我嘗試下面的代碼:爲什麼調用函數比不調用函數更快?

public class Test { 
    public static void main(String[] args) { 
     int x = 9, y = 9, z = 0; 
     long startTime = System.currentTimeMillis(); 
     // System.out.println("loop one start time = " + startTime); 
     for (int i = 0; i < 10000; i++) { 
      for (int j = 0; j < 10000; j++) { 
       z = x + y; 
      } 
     } 
     System.out.println("loop one use time = " + (System.currentTimeMillis() - startTime) + ",z = " + z); 

     startTime = System.currentTimeMillis(); 
     // System.out.println("loop two start time = " + startTime); 
     for (int i = 0; i < 10000; i++) { 
      for (int j = 0; j < 10000; j++) { 
       z = sum(x, y); 
      } 
     } 
     System.out.println("loop two use time = " + (System.currentTimeMillis() - startTime) + ",z = " + z); 

    } 

    public static int sum(int x, int y) { 
     int t; 
     t = x + y; 
     return t; 
    } 
} 

輸出到控制檯:

loop one use time = 216,z = 18 
loop two use time = 70,z = 18. 

看來,第二個循環花更少的時間,比第一個! 我不明白爲什麼會發生這種情況。感謝您的幫助。


更新: 我交換的兩個循環,現在一環花費較少的時間!

loop two use time = 219,z = 18 
loop one use time = 69,z = 18 
+4

快速問題 - 如果在代碼中交換兩個循環,結果如何? –

+4

可能的重複[如何在Java中編寫正確的微基準?](http://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java ) - 因爲你如何測量不太可能產生任何有用的東西。 –

+0

無法在我的PC上確認 - 循環一次使用時間= 2,z = 18 循環兩次使用時間= 5,z = 18. :-) – Smutje

回答

1

Writing a correct micro-benchmark非常耗時且容易出錯。我建議只使用已有的庫來進行微基準測試,例如Caliper,這是專門爲此而設計的。

你的微基準有相當多的缺陷,這將導致不可預測的結果:

  1. 你正在做不熱身。
  2. 您正在對主方法內的兩種方法進行基準測試,從而給JIT編譯器更難以優化代碼的時間。
  3. 代碼「z = x + y;」實際上降至「z = 9 + 9」;「並且在循環中不會改變,所以循環可以完全優化到簡單表達式「z = 18」。

不管怎麼說,這是與顯卡做了相應的基準代碼:

@VmOptions("-server") 
public class Test { 

    @Benchmark 
    public int timeSum1(long reps) { 
     int dummy = 0; 
     int x = 9, y = 9; 
     for (int j = 0; j < reps; j++) { 
      dummy = x + y; 
     } 
     return dummy; 
    } 

    @Benchmark 
    public int timeSum2(long reps) { 
     int dummy = 0; 
     int x = 9, y = 9; 
     for (int j = 0; j < reps; j++) { 
      dummy = sum(x, y); 
     } 
     return dummy; 
    } 

    public static int sum(int x, int y) { 
     int t; 
     t = x + y; 
     return t; 
    } 
} 

你可以看看結果對於這個基準測試在這裏:

結果如預期:兩種方法大致相同,因爲它們可以由JIT編譯器內聯。使用-server運行這兩種方法仍然需要大致相同的時間,但優化得更好一些。

0

從閱讀評論我有這個想法,嘗試下面的代碼

public class Test { 
    public static void main(String[] args) { 
     int x = 9, y = 9, z = 0; 
     for (int i = 0; i < 10000; i++) { 
      for (int j = 0; j < 10000; j++) { 
       z = x + y; 
       // z = sum(x, y); 
      } 
     } 
     long startTime = System.currentTimeMillis(); 
     // System.out.println("loop one start time = " + startTime); 
     for (int i = 0; i < 10000; i++) { 
      for (int j = 0; j < 10000; j++) { 
       z = x + y; 
      } 
     } 
     System.out.println("loop one use time = " 
       + (System.currentTimeMillis() - startTime) + ",z = " + z); 

     startTime = System.currentTimeMillis(); 
     // System.out.println("loop two start time = " + startTime); 
     for (int i = 0; i < 10000; i++) { 
      for (int j = 0; j < 10000; j++) { 
       z = sum(x, y); 
      } 
     } 
     System.out.println("loop two use time = " 
       + (System.currentTimeMillis() - startTime) + ",z = " + z); 

    } 

    public static int sum(int x, int y) { 
     int t; 
     t = x + y; 
     return t; 
    } 
} 

將呈現什麼樣的結果,無論是循環具有相同的時間,造成JVM有所回暖其內部功能和準備發球在他的腳趾。 :)

這也意味着你不能直接關聯某些代碼所使用的時間直接關係到它的算法,那麼你需要控制相同的環境和參數來控制代碼的耗時。