【问题标题】:Performance: greater / smaller than vs not equal to性能:大于/小于 vs 不等于
【发布时间】:2013-09-03 15:40:47
【问题描述】:

我想知道两者在性能上是否存在差异

检查一个值是否大于/小于另一个值

for(int x = 0; x < y; x++); // for y > x

检查一个值是否不等于另一个

for(int x = 0; x != y; x++); // for y > x

为什么?

另外:如果我比较为零,是否还有进一步的区别?

如果答案也考虑对代码的组装视图,那就太好了。

编辑: 正如你们大多数人指出的那样,性能差异当然可以忽略不计,但我对 cpu 级别的差异感兴趣。哪个操作更复杂?

对我来说,学习/理解这项技术更多的是一个问题。

我删除了 Java 标记,这是我不小心添加的,因为这个问题通常不仅仅基于 Java,抱歉。

【问题讨论】:

标签: performance jvm comparison


【解决方案1】:

你仍然应该做更清晰、更安全和更容易理解的事情。这些微调讨论通常是在浪费您的时间,因为

  • 它们很少能产生可衡量的差异
  • 当它们产生影响时,如果您使用不同的 JVM 或处理器,这种情况可能会发生变化。即没有警告。

注意:生成的机器也会随着处理器或 JVM 的变化而变化,因此在大多数情况下,即使您非常熟悉汇编代码,查看这也不是很有帮助。

更重要的是软件的可维护性。

【讨论】:

  • +1 我一直很喜欢您对有关性能和效率的问题的回答。特别是因为我太不擅长了:)
  • @RohitJain 或者你意识到这并不像猜测什么是个好主意那么容易。即使比较晦涩,也很难找到一个出于性能原因而更好的示例。
  • @PeterLawrey +1 同意。除非您的应用程序需要尽可能最佳地运行(例如在内存/计算能力有限的环境下运行,或者需要尽可能多的汁液的一些超复杂模拟),否则甚至不应该考虑为了性能而考虑模糊性。否则你就是在浪费所有的空闲空间,哟。
  • @SuperCat 同意,你可以证明越晦涩的代码实际上越快。 ;) 这经常丢失。顺便说一句,JVM 优化了常见/特定的代码模式。这意味着如果您使用不常见的模式(就 JVM 而言),您的代码可能会更慢而不是更快,即使理论上如果您使用不同的编译器可能会更快。
  • 我不确定为什么这是投票率最高的答案,因为 OP 提出了一个与性能有关的问题,而不是软件工程最佳实践。
【解决方案2】:

性能完全可以忽略。这里有一些代码可以证明这一点:

public class OpporatorPerformance {
    static long y = 300000000L;

    public static void main(String[] args) {
        System.out.println("Test One: " + testOne());
        System.out.println("Test Two: " + testTwo());
        System.out.println("Test One: " + testOne());
        System.out.println("Test Two: " + testTwo());
        System.out.println("Test One: " + testOne());
        System.out.println("Test Two: " + testTwo());
        System.out.println("Test One: " + testOne());
        System.out.println("Test Two: " + testTwo());

    }

    public static long testOne() {
        Date newDate = new Date();
        int z = 0;
        for(int x = 0; x < y; x++){ // for y > x
            z = x;
        }
        return new Date().getTime() - newDate.getTime();
    }

    public static long testTwo() {
        Date newDate = new Date();
        int z = 0;
        for(int x = 0; x != y; x++){ // for y > x
            z = x;
        }
        return new Date().getTime() - newDate.getTime();
    }

}

结果:

Test One: 342
Test Two: 332
Test One: 340
Test Two: 340
Test One: 415
Test Two: 325
Test One: 393
Test Two: 329

【讨论】:

  • +1 在我上次运行时,我的笔记本电脑上收到了Test One: 113 Test Two: 113
  • 您应该使用 System.nanoTime() 进行基准测试,这样可以提高您的精度。
  • @RohitJain,谢谢!不知怎的,我还没有学会。我喜欢它的一点是,现在我不需要导入java.util.Date。虽然,javadoc 确实说“此方法提供纳秒精度,但不一定提供纳秒分辨率(即值更改的频率) - 除非分辨率至少与 currentTimeMillis() 一样好,否则无法保证。 "所以,我不一定相信额外精度的准确性。
  • 我不相信Date().getTime() - 您正在创建一个新对象只是为了测量时间,这实际上可能会掩盖基准。为什么不使用nanoTime() 或至少currentTimeMillis()(顺便说一句,这是最快的调用之一)?
【解决方案3】:

现在 6 年后,在仍然偶尔收到来自此问题的通知之后,我想补充一些我在计算机科学学习期间获得的见解。

把上面的语句放到一个小程序中,编译一下……

public class Comp {
    public static void main(String[] args) {
        int y = 42;

        for(int x = 0; x < y; x++) {
            // stop if x >= y
        }

        for(int x = 0; x != y; x++) {
            // stop if x == y
        }
    }
}

...我们得到以下字节码:

  public static void main(java.lang.String[]);
    Code:
       // y = 42
       0: bipush        42  
       2: istore_1

       // first for-loop
       3: iconst_0
       4: istore_2
       5: iload_2
       6: iload_1
       7: if_icmpge     16      // jump out of loop if x => y
      10: iinc          2, 1
      13: goto          5

       // second for-loop
      16: iconst_0
      17: istore_2
      18: iload_2
      19: iload_1
      20: if_icmpeq     29      // jump out of loop if x == y
      23: iinc          2, 1
      26: goto          18

      29: return

正如我们所见,在字节码级别,两者都以相同的方式处理,并使用单个字节码指令进行比较。

如前所述,如何将字节码翻译成汇编程序/机器码取决于 JVM。 但通常这种条件跳转可以翻译成一些汇编代码,如下所示:

; condition of first loop
CMP eax, ebx
JGE label  ; jump if eax > ebx

; condition of second loop
CMP eax, ebx
JE  label  ; jump if eax == ebx

在硬件级别上,JGE 和 JE 具有相同的复杂性。

总而言之:就性能而言,x &lt; yx != y 在硬件级别上理论上是相同的,并且一个本身并不比另一个快或慢。

【讨论】:

  • 一场大流行之后,您仍然会收到有关此问题的通知。我很确定除了进行完整的计算机科学研究之外,还有更快的方法可以明确地解决这个问题,但我明白了,你做你必须做的。祝贺您的学习,并感谢您的回答,您应该接受它作为正确的回答。这是当之无愧的!
【解决方案4】:

很少有性能影响,但第一个更可靠,因为它可以处理两种特殊情况

  1. y
  2. x 或 y 在块内被弄乱了。

【讨论】:

  • 值得注意的是,支持!= 的类型多于&lt;(例如,所有迭代器,而不仅仅是随机访问迭代器),因此!= 通常用于一致性。
【解决方案5】:

理论上的表现是一样的。当您执行小于或不等于运算时,在处理器级别您实际上执行减法运算并检查结果中是否启用了负标志或零标志。理论上性能是一样的。因为区别只是检查标志集。

【讨论】:

    【解决方案6】:

    其他人似乎已经从测量的角度回答了问题,但从机器级别来看,您会对算术逻辑单元 (ALU) 感兴趣,它处理“普通计算机”上的数学位。 How does less than and greater than work on a logical level in binary? 中似乎有一个相当不错的细节以获取完整的详细信息。

    从纯粹的逻辑层面来看,简短的回答是,判断某物是否不是某物比判断某物是否与某物相关更容易,但是这可能已在您的标准个人计算机或服务器中进行了优化,所以您只会在小型个人构建中看到实际收益,例如用于无人机或其他微技术的机载计算机。

    【讨论】:

      【解决方案7】:

      想知道每个测试是否嵌套,结果是否相同?

      for(int x = 0; x < y; x++)
      {   
        for(int x2 = 0; x2 < y; x2++)  {}   
      }
      
      for(int x = 0; x != y; x++)
      {
        for(int x2 = 0; x2 != y; x2++) {}    
      }
      

      【讨论】:

      • 为什么会获得赞成票?自己测试一下,然后给我们一个答案,而不是另一个问题。
      猜你喜欢
      • 1970-01-01
      • 2011-01-25
      • 1970-01-01
      • 2012-09-11
      • 1970-01-01
      • 2013-09-02
      • 2012-10-13
      • 2011-12-21
      • 2018-11-23
      相关资源
      最近更新 更多