2013-06-18 27 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]在它内部被宣告,并且不在外部使用