2

最近我做了一个不完整的非图求解器。求解器基于迭代线求解方法。一些代码是这样的:

方法一:

for(; j<i; j++){
     if(a[j] == 0) break;
}

方法二:

for(; j<i && a[j]!=0; j++);

这段代码在我的程序中出现了很多次。

我认为方法1和方法2都做了同样的事情。但是当我time nonogram在 linux 机器上使用时,当 nonogram 的大小在 5 x 10 左右时,时间非常接近,大多数时候方法 2 更快。当大小为 30x40 时,我运行程序大约 10 次,大多数时候方法 1 运行速度比方法 2 快(时间差在 0.2s 左右)。是随机问题吗?如果这是一个随机问题,我将使用方法 2 而不是方法 1。它们在编译器实现上真的不同吗?谢谢你。

4

1 回答 1

10

我为此做了两个基本的代码测试并查看了汇编代码。这就是我得到的。

方法一:

public class TestBreak {
    public static void main(String[] args) {
        int i = 10;
        int j = 5;
        int a[] = {5, 10, 6, 90, 0, 1, 0, 7, 10};
        for(; j<i; j++){
            if(a[j] == 0) break;
        }
    }
}

方法二:

public class TestBreak2 {
    public static void main(String[] args) {
        int i = 10;
        int j = 5;
        int a[] = {5, 10, 6, 90, 0, 1, 0, 7, 10};
        for(; j<i && a[j] != 0; j++){
        }
    }
}

方法一的汇编代码:

public class TestBreak {
  public TestBreak();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: bipush        10
       2: istore_1      
       3: iconst_5      
       4: istore_2      
       5: bipush        9
       7: newarray       int
       9: dup           
      10: iconst_0      
      11: iconst_5      
      12: iastore       
      13: dup           
      14: iconst_1      
      15: bipush        10
      17: iastore       
      18: dup           
      19: iconst_2      
      20: bipush        6
      22: iastore       
      23: dup           
      24: iconst_3      
      25: bipush        90
      27: iastore       
      28: dup           
      29: iconst_4      
      30: iconst_0      
      31: iastore       
      32: dup           
      33: iconst_5      
      34: iconst_1      
      35: iastore       
      36: dup           
      37: bipush        6
      39: iconst_0      
      40: iastore       
      41: dup           
      42: bipush        7
      44: bipush        7
      46: iastore       
      47: dup           
      48: bipush        8
      50: bipush        10
      52: iastore       
      53: astore_3      
      54: iload_2       
      55: iload_1       
      56: if_icmpge     74
      59: aload_3       
      60: iload_2       
      61: iaload        
      62: ifne          68
      65: goto          74
      68: iinc          2, 1
      71: goto          54
      74: return        
}

方法2的汇编代码:

public class TestBreak2 {
  public TestBreak2();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: bipush        10
       2: istore_1      
       3: iconst_5      
       4: istore_2      
       5: bipush        9
       7: newarray       int
       9: dup           
      10: iconst_0      
      11: iconst_5      
      12: iastore       
      13: dup           
      14: iconst_1      
      15: bipush        10
      17: iastore       
      18: dup           
      19: iconst_2      
      20: bipush        6
      22: iastore       
      23: dup           
      24: iconst_3      
      25: bipush        90
      27: iastore       
      28: dup           
      29: iconst_4      
      30: iconst_0      
      31: iastore       
      32: dup           
      33: iconst_5      
      34: iconst_1      
      35: iastore       
      36: dup           
      37: bipush        6
      39: iconst_0      
      40: iastore       
      41: dup           
      42: bipush        7
      44: bipush        7
      46: iastore       
      47: dup           
      48: bipush        8
      50: bipush        10
      52: iastore       
      53: astore_3      
      54: iload_2       
      55: iload_1       
      56: if_icmpge     71
      59: aload_3       
      60: iload_2       
      61: iaload        
      62: ifeq          71
      65: iinc          2, 1
      68: goto          54
      71: return        
}

如您所见,唯一的区别是方法 1 的汇编代码中有一行:

62: ifne          68

除此之外,它们会生成相似的字节码,因此性能差异可能并不是真正的东西。

如果您真的想测量哪个更快,请编写一个微基准测试。为此,请遵循此处解释的规则:如何在 Java 中编写正确的微基准测试?.

另一条信息:如果您真的想发现应用程序中的性能瓶颈,请使用分析器,它会明确告诉您哪些方法比其他方法消耗更多的 cpu,然后努力解决性能问题那(那些)方法而不是猜测问题可能出在哪里。

关于如何生成字节码,请阅读javap命令,特别是javap -c.

于 2013-10-22T05:16:06.967 回答