正在做!(!a&& b)效率低于|| !B'

时间:2012-05-30 05:33:38

标签: java performance logical-operators

我有一个路径查找算法,它运行了很多次并且必须非常高效,所以我想知道我能做些什么来提高性能。我有一句if声明:

if (!(n != 1 && map.isCornerObstructed(p)) {
    // Do stuff...
}

在我看来,双重反转需要比这个逻辑上等效的版本稍长一些:

if (n == 1 || !map.isCornerObstructed(p)) {
    // Do stuff...
}

问题是前者在代码的上下文中更具可读性,所以如果我不知道结果会是什么,我有点不愿意改变它。

一个比另一个更有效吗?或者Java编译器是否足够智能以自动优化这样的事情?

5 个答案:

答案 0 :(得分:4)

请专注于优化算法的复杂性,而不是这些微优化。

对于这种情况,我看到一个比较(!===),一个逻辑运算符,一个否定。在n!= 1的情况下,逻辑运算的数量是相同的。在n == 1的情况下,第一种情况的逻辑运算的数量大于第二种情况。如果有更多n!= 1个案例,那么可能无关紧要。如果有更多n == 1个案例,那么第二个案例可能会快一点。但是由于整个JIT编译器都在后面工作,我不知道究竟发生了什么。微优化可能适用于C / C ++代码,但我真的怀疑它对Java的影响。

答案 1 :(得分:4)

代码

Set<String> set = new HashSet<String>();
int n = set.size();
Object o = new Object();
if (!(n != 1 && set.contains(o))) {
  System.out.println("Foo");
  // Do stuff...
}

生成字节码

 0  new java.util.HashSet [16]
 3  dup
 4  invokespecial java.util.HashSet() [18]
 7  astore_1 [set]
 8  aload_1 [set]
 9  invokeinterface java.util.Set.size() : int [19] [nargs: 1]
14  istore_2 [n]
15  new java.lang.Object [3]
18  dup
19  invokespecial java.lang.Object() [8]
22  astore_3 [o]
23  iload_2 [n]
24  iconst_1
25  if_icmpeq 38
28  aload_1 [set]
29  aload_3 [o]
30  invokeinterface java.util.Set.contains(java.lang.Object) : boolean [25] [nargs: 2]
35  ifne 46
38  getstatic java.lang.System.out : java.io.PrintStream [29]
41  ldc <String "Foo"> [35]
43  invokevirtual java.io.PrintStream.println(java.lang.String) : void [37]
46  return

代码

Set<String> set = new HashSet<String>();
int n = set.size();
Object o = new Object();
if (n == 1 || !set.contains(o)) {
  System.out.println("Foo");
  // Do stuff...
}

生成字节码

 0  new java.util.HashSet [16]
 3  dup
 4  invokespecial java.util.HashSet() [18]
 7  astore_1 [set]
 8  aload_1 [set]
 9  invokeinterface java.util.Set.size() : int [19] [nargs: 1]
14  istore_2 [n]
15  new java.lang.Object [3]
18  dup
19  invokespecial java.lang.Object() [8]
22  astore_3 [o]
23  iload_2 [n]
24  iconst_1
25  if_icmpeq 38
28  aload_1 [set]
29  aload_3 [o]
30  invokeinterface java.util.Set.contains(java.lang.Object) : boolean [25] [nargs: 2]
35  ifne 46
38  getstatic java.lang.System.out : java.io.PrintStream [29]
41  ldc <String "Foo"> [35]
43  invokevirtual java.io.PrintStream.println(java.lang.String) : void [37]
46  return

完全相同。因此,无论您如何精确地衡量它,都不会有所有的性能差异。编译后的代码相同。

(请注意,原因是javac实际上将if语句分解为单独的条件测试和分支,因此它实际上解决了每种可能性的路径。)

答案 2 :(得分:1)

我在这里担心的是map.isCornerObstructed(p)调用比什么都重要,布尔逻辑很快,但方法调用不是那么多。

我会选择第二种选择 - 这似乎是最容易阅读和最有效的选择。

正如评论所指出的那样,&amp;&amp;和||短路所以你想要最简单的测试方法,使用包装的反转只是另一个需要执行的层。

答案 3 :(得分:0)

如果你在这里和那里做过那个陈述,谁在乎呢。任何一个最多可达几个cpu周期。

答案 4 :(得分:0)

第二个可以更优化。 但这取决于执行这部分代码的次数,

更具体地说,在你的第二个选项中:

if (n == 1 || !map.isCornerObstructed(p)) {
// Do stuff...
}

如果n == 1为真,则java将不执行!map.isCornerObstructed(p),并且n == 1比!map.isCornerObstructed(p)更优化,因此您必须编写“if”语句在大多数情况下,第一个和更简单的陈述显示答案,

如果你对java optimize(!(n!= 1&amp;&amp; map.isCornerObstructed(p))是否有疑问,你可以简单地编写一个测试用例, 在循环中运行每个语句1000000次并使用System.currentmils计算每个方法的时间成本,然后你去了