2013-06-18 2 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

テストを何回実行しましたか? 2つの変種をループで何度も試してみましたか?あなたはあなたの呼び出しの順序を逆転しようとしましたか? –

+0

[jmh](http://openjdk.java.net/projects/code-tools/jmh/)を使用してベンチマークを実装しようとします。これはjvm開発者が設計した特別なツールです。独自のベンチマークではなく、このツールを使用して多くの間違いを避けることができます。 –

+0

私は10回試して、2番目は常により速く実行されます。 – 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 - ループの最初の反復の類似した値になりますが、その後、結果が収束し、もはや有意差はありません。

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

さらに、時にはmethod1がより速く見えるes method2 - これはおそらく測定の不正確さによるものです。

+0

同じ質問ですが、なぜmethod2がmethod1 ...よりも速いのですか...ベンチマークのためのLol .... + 1 ..... –

+1

ベンチマークツールを使用して私の所見を再度検証する必要があると思います。私はそれが終わったらすぐに回答を掲示します。 – Amber

0

jvmを何度かウォーミングアップした後、method2がmethod1よりも速いことがわかります。ここで

は私のリファクタリングコードです:

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と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はそれが性能をテストする良い方法はないと述べたように。指摘する

シング:宣言されたサイズ(ジョシュア・ブロックの著書効果的なJavaの項目51で:文字列連結のパフォーマンスを注意してください)とのStringBuilderを使用
からは(法2を好む)ことが可能に:文字列[ビルダー]はその中に埋め込まれていて、外では使用しません

関連する問題