2013-06-18 79 views
6

以下代碼證明method1比method2快。任何人都可以請評論這種行爲的原因是什麼。本地成員更快或實例成員

class Trial { 
     String _member; 
     void method1() { 
      for(int i=0;i<30480;i++) { 
       _member += "test"; 
      } 
     } 
     void method2() { 
      String temp=""; 
      for(int i=0;i<30480;i++) { 
       temp += "test"; 
      } 
      _member = temp; 
     } 

     public static void main(String args[]) { 
      Trial t = new Trial(); 
      long startTime1 = System.currentTimeMillis(); 
      t.method1(); 
      long endTime1 = System.currentTimeMillis(); 
      long startTime2 = System.currentTimeMillis(); 
      t.method2(); 
      long endTime2 = System.currentTimeMillis(); 
      System.out.println(endTime1 - startTime1); 
      System.out.println(endTime2 - startTime2); 
     } 
    } 
+1

你運行過多少次測試?你是否嘗試過在循環中多次運行這兩個變體?您是否試過並顛倒了您的通話順序? –

+0

嘗試使用[jmh](http://openjdk.java.net/projects/code-tools/jmh/)實施基準測試。它是由jvm開發人員設計的特殊工具。使用這個工具可以避免很多錯誤,而不是您自己的基準。 –

+0

我試了10次,第二次總是跑得更​​快。 – simaremare

回答

12

下面的代碼證明方法1比方法2快

不是,它不會證明它。

這取決於很多因素。當我運行這段代碼,我得到

1403 
1248 

所以在我的環境中,你的代碼來「證明」方法1比方法2

進行基準測試時,您需要注意緩存和JVM熱身等效果。

更多信息見。


我稍微重構了main方法:

... 

static void doBenchmark() { 
    Trial t = new Trial(); 

    long startTime1 = System.currentTimeMillis(); 
    t.method1(); 
    long endTime1 = System.currentTimeMillis(); 

    long startTime2 = System.currentTimeMillis(); 
    t.method2(); 
    long endTime2 = System.currentTimeMillis(); 

    System.out.println(endTime1 - startTime1); 
    System.out.println(endTime2 - startTime2); 
} 

public static void main(String args[]) { 

    for (int i = 0; i < 20; i++) { 
     doBenchmark(); 
     System.out.println("----"); 
    } 
} 

這導致類似的值的第一迭代for -loop的,但隨後的結果收斂和顯著再沒有什麼不同:

1396 
1133 
---- 
1052 
1070 
---- 
688 
711 
---- 
728 
726 
---- 
715 
709 
---- 
... 

即使有時method1似乎更快和有點es method2 - 這很可能是由於測量不準確。

+0

同樣的問題,爲什麼method2比method1快...... Lol .... + 1用於基準測試..... –

+1

我想我需要使用一些基準測試工具再次驗證我的發現。我會盡快發佈回覆。 – Amber

0

熱身jvm一段時間後,您會看到方法2比方法1快。

這裏是我重新分解代碼:

class Trial { 
String _member; 

    void method1() { 
    for (int i = 0; i < 30480; i++) { 
     _member += "test"; 
    } 
    } 

    void method2() { 
    String temp = ""; 
    for (int i = 0; i < 30480; i++) { 
     temp += "test"; 
    } 
    _member = temp; 
    } 

    public static void main(String args[]) { 
    Trial t = new Trial(); 

    for (int i = 0; i < 10; i++) { //warm up jvm 
     t.method1(); 
     t.method2(); 
    } 

    t = new Trial(); 

    long startTime1 = System.currentTimeMillis(); 
    t.method1(); 
    long endTime1 = System.currentTimeMillis(); 
    long startTime2 = System.currentTimeMillis(); 
    t.method2(); 
    long endTime2 = System.currentTimeMillis(); 
    System.out.println(endTime1 - startTime1); 
    System.out.println(endTime2 - startTime2); 
    } 
} 

這裏是結果:

---- 
2910 
2894 
---- 

但對於實際的標杆,你應該運行多次,觀察的統計行爲,只有這樣你才能得出任何結論!

+0

嗯,你犯了和我在重構過程中一樣的錯誤:D爲了真正比較這些方法,你需要在'for'循環內重新實例化'Trial'。否則,你可以使用String _member變量中的舊內容。由於那裏已經有內容,所以額外的連接將花費更多的時間。 –

+0

我編輯了我的答案,仍然method2更快......:P –

0

我修改了測試次數,但不是方法,這裏用StringBuilder2500 at 3000時間更快!

class Trial { 
    StringBuilder _member = new StringBuilder(243840); 
    void method1() { 
     for (int i = 0; i < 30480; i++) { 
      _member.append("test"); 
     } 
    } 

    void method2() { 
     final StringBuilder temp = new StringBuilder(243840); 
     for (int i = 0; i < 30480; i++) { 
      temp.append("test"); 
     } 
     _member = temp; 
    } 
    public static void main(final String args[]) { 
     long startTime1 = System.nanoTime(); 
     new Trial().method1(); 
     long endTime1 = System.nanoTime(); 
     long startTime2 = System.nanoTime(); 
     new Trial().method2(); 
     long endTime2 = System.nanoTime(); 
     System.out.println(endTime1 - startTime1); 
     System.out.println(endTime2 - startTime2); 
     System.out.println("------------------"); 
     startTime1 = System.nanoTime(); 
     new Trial().method1(); 
     endTime1 = System.nanoTime(); 
     startTime2 = System.nanoTime(); 
     new Trial().method2(); 
     endTime2 = System.nanoTime(); 
     System.out.println(endTime1 - startTime1); 
     System.out.println(endTime2 - startTime2); 
    } 
} 

輸出:

method1 then method2 with += in MILLIisecond 
5563 
5844 
............................................ 
5437 
6344 

method2 then method1 with += in MILLIisecond 
4625 
5969 
------------------ 
6531 
4891 

===================================================== 

method1 then method2 with StringBuilder in NANOsecond 
3530337 
2074286 
------------------ 
2058641 
1983493 
..................................................... 

method2 then method1 with StringBuilder in NANOsecond 
3430883 
1698819 
------------------ 
2065626 
2144406 

從而@Andreas說是不是測試性能的好辦法。

要指出的:使用StringBuilder的與聲明的大小(在約書亞布洛赫的書有效的Java 項目51:當心字符串連接的性能
- 寧願方法2()時可能:字符串[ Builder]在它內部被宣告,並且不在外部使用