Java 条件运算符速度与 Hotspot VM 版本

发布于 2024-08-03 20:54:51 字数 2851 浏览 5 评论 0原文

请考虑以下 java 源代码:

package com.stackoverflow;

 public class CondSpeed {
 private static final long COUNT = 1000000000;
 private static final long OUTER_COUNT = 15;

 private static long notEqOperator = 0L;
  private static long notOperator = 0L;
private static long equalsFalse = 0L;

public CondSpeed() {
 super();
}

public static void main(String[] args) {

 for(int outCount = 0;outCount < OUTER_COUNT;outCount++){
  notEqOperator += testNotEaualsOperator();
  equalsFalse += testEqualFalse();
  notOperator += testNotOperator();
 }

 long avrForNotEqOperator = (notEqOperator / OUTER_COUNT);
 long avrForEqualsFalse = (equalsFalse / OUTER_COUNT);
 long avrForNotOperator = (notOperator / OUTER_COUNT);

 System.out.println("Avr for Not Equals Operator: "+avrForNotEqOperator);
 System.out.println("Avr for Equals \"false\" Operator: "+avrForEqualsFalse);
 System.out.println("Avr for Not Operator: "+avrForNotOperator);

}

private static long testEqualFalse(){
 long now = System.currentTimeMillis();

 for(long i = 0;i < COUNT;i++){
  boolean truFalse = returnTrueOrFalse();

  if(truFalse == false){
   //do nothing...
  }
 }

 return (System.currentTimeMillis() - now);
}


   private static long testNotOperator(){
 long now = System.currentTimeMillis();

 for(long i = 0;i < COUNT;i++){
  boolean truFalse = returnTrueOrFalse();

  if(!truFalse){
//do nothing...
  }
 }

 return (System.currentTimeMillis() - now);
}

private static long testNotEaualsOperator(){
 long now = System.currentTimeMillis();

 for(long i = 0;i < COUNT;i++){
  boolean truFalse = returnTrueOrFalse();

  if(truFalse != true){
   //do nothing...
  }
 }

 return (System.currentTimeMillis() - now);
}

private static boolean isFalse;
private static boolean returnTrueOrFalse(){
 if(isFalse){
  isFalse = false;
 }
 else{
  isFalse = true;
 }
 return isFalse;
}

}

如您所见,这是针对 3 个版本的 if(false) 条件。

  • 我感兴趣的是为什么不同条件语句的结果首先不同。 ((我知道这显然是编译器将 .java 解释为字节码的方式。))还有比这更多的吗?
  • 第二。查看不同 Hotspot VM 的差异。见底部。这是因为虚拟机在各个版本上的更新/改进吗?或者还有更多的事情吗?
  • 这是测试此类内容的最佳方法吗?

---结果 Mac OS X---

JavaVM HotSpot 1.6.0

不等于运算符的 Avr:1937
Avr 等于“假”运算符:1937
非运算符 Avr:1941

JavaVM HotSpot 1.5.0

不等于运算符 Avr:5023
Avr 等于“false”运算符:5035
非运算符 Avr:5067

JavaVM HotSpot 1.4.2

不等于运算符 Avr:3993
Avr 等于“false”运算符:4015
非运算符 Avr:4009

JavaVM HotSpot 1.4.0

不等于运算符 Avr:3961
等于“假”运算符的 Avr:3960
非运算符 Avr:3961

谢谢。

Please consider the following java source:

package com.stackoverflow;

 public class CondSpeed {
 private static final long COUNT = 1000000000;
 private static final long OUTER_COUNT = 15;

 private static long notEqOperator = 0L;
  private static long notOperator = 0L;
private static long equalsFalse = 0L;

public CondSpeed() {
 super();
}

public static void main(String[] args) {

 for(int outCount = 0;outCount < OUTER_COUNT;outCount++){
  notEqOperator += testNotEaualsOperator();
  equalsFalse += testEqualFalse();
  notOperator += testNotOperator();
 }

 long avrForNotEqOperator = (notEqOperator / OUTER_COUNT);
 long avrForEqualsFalse = (equalsFalse / OUTER_COUNT);
 long avrForNotOperator = (notOperator / OUTER_COUNT);

 System.out.println("Avr for Not Equals Operator: "+avrForNotEqOperator);
 System.out.println("Avr for Equals \"false\" Operator: "+avrForEqualsFalse);
 System.out.println("Avr for Not Operator: "+avrForNotOperator);

}

private static long testEqualFalse(){
 long now = System.currentTimeMillis();

 for(long i = 0;i < COUNT;i++){
  boolean truFalse = returnTrueOrFalse();

  if(truFalse == false){
   //do nothing...
  }
 }

 return (System.currentTimeMillis() - now);
}


   private static long testNotOperator(){
 long now = System.currentTimeMillis();

 for(long i = 0;i < COUNT;i++){
  boolean truFalse = returnTrueOrFalse();

  if(!truFalse){
//do nothing...
  }
 }

 return (System.currentTimeMillis() - now);
}

private static long testNotEaualsOperator(){
 long now = System.currentTimeMillis();

 for(long i = 0;i < COUNT;i++){
  boolean truFalse = returnTrueOrFalse();

  if(truFalse != true){
   //do nothing...
  }
 }

 return (System.currentTimeMillis() - now);
}

private static boolean isFalse;
private static boolean returnTrueOrFalse(){
 if(isFalse){
  isFalse = false;
 }
 else{
  isFalse = true;
 }
 return isFalse;
}

}

As you can see it is a test against 3 versions of if(false) conditions.

  • I am interested in why the results are firstly different in the various condition statements. ((I know that its obviously the way the compiler interpretes the .java into bytecode.)) Is there more to it than this?
  • Secondly. Look at the differences in different Hotspot VMs. See bottom. Is this because of updates/improvements the the VM over versions? Or is there more to it?
  • Is this the best way to test something like this?

---Results Mac OS X---

JavaVM HotSpot 1.6.0

Avr for Not Equals Operator: 1937
Avr for Equals "false" Operator: 1937
Avr for Not Operator: 1941

JavaVM HotSpot 1.5.0

Avr for Not Equals Operator: 5023
Avr for Equals "false" Operator: 5035
Avr for Not Operator: 5067

JavaVM HotSpot 1.4.2

Avr for Not Equals Operator: 3993
Avr for Equals "false" Operator: 4015
Avr for Not Operator: 4009

JavaVM HotSpot 1.4.0

Avr for Not Equals Operator: 3961
Avr for Equals "false" Operator: 3960
Avr for Not Operator: 3961

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

っ左 2024-08-10 20:54:51

!、!= 和 == 之间的差异看起来像随机噪声 - 您真的希望它们达到完全相同的毫秒数吗?

然而,JVM 版本的改进几乎肯定是真实的,尽管它可能非常特定于特定的代码段,即某些落在需要正确处理的复杂性阈值内的问题。即使稍有不同也可能不会显示相同的结果。

为了改进测试,请计算每次测试运行的标准差,并查看它们是否存在统计差异(或者只是打印出所有 10 个结果并观察它们)。

The differences between !, != and == look like random noise - were you really expecting them to come out to exactly the same number of millisecs?

The improvement with JVM version, however, is almost certainly real, though it is likely very specific to that particular piece of code, a matter of something falling within a complexity threshold to be handled properly. Something even slightly different might not show the same results.

To improve testing, calculate the standard deviation of each test run and see if they are statistically different (or just print out all 10 results and eyeball them).

千年*琉璃梦 2024-08-10 20:54:51

像这样的微基准测试不会告诉你任何有趣的事情。您正在进行十亿次测试迭代,结果会在几秒钟内返回。每次迭代有多少个周期?微基准测试没有做任何工作。

Microbenchmarks like this don't tell you anything interesting. You are doing a billion iterations of the test and the result comes back in seconds. How many cycles per iteration is that? The microbenchmark isn't doing any work.

弄潮 2024-08-10 20:54:51

如果 JVM 做得不错,它会检测到以下语句不会执行任何影响计算的操作,并将完全优化掉它们。

if (truFalse != true) {
     //do nothing...
}
...
if (truFalse == false) {
   //do nothing...
}
...
if (!truFalse) {
   //do nothing...
}

换句话说,您的基准测试可能在这三种情况下没有测量到任何不同的东西。

吸取的教训:

  1. 很难确定您从微基准测试中获得了有意义的数字。
  2. 不同 JVM 之间的相对数字可能存在很大差异。对一个 JVM 有帮助的“聪明技巧”实际上可能会妨碍另一个 JVM。
  3. 在针对每个平台对 Java 程序进行微优化方面,编译器可能比您做得更好。

最好的策略是将微观优化留给编译器,而专注于“宏观”问题,例如使用最佳算法。另外,使用执行分析器来找出哪些地方值得花时间进行优化。

If the JVM is doing a decent job it will detect that the following statements do nothing that affects the computation and will completely optimize them away.

if (truFalse != true) {
     //do nothing...
}
...
if (truFalse == false) {
   //do nothing...
}
...
if (!truFalse) {
   //do nothing...
}

In other words, your benchmarks are probably not measuring anything different in the three cases.

Lessons to learn:

  1. It is difficult to be sure that you are getting meaningful numbers from a microbenchmark.
  2. The relative numbers can vary significantly from one JVM to another. A "clever trick" that helps on one JVM could actually get in the way on another.
  3. A compiler is likely to do a far better job of micro-optimizing your Java programs for each platform than you are.

The best strategy is to leave micro-optimization to the compiler, and focus on the "macro" issues like using the best algorithm. Also, use a execution profiler to figure out where it is worthwhile spending time to optimize.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文