我有一个路径查找算法,它运行了很多次并且必须非常高效,所以我想知道我能做些什么来提高性能。我有一句if声明:
if (!(n != 1 && map.isCornerObstructed(p)) {
// Do stuff...
}
在我看来,双重反转需要比这个逻辑上等效的版本稍长一些:
if (n == 1 || !map.isCornerObstructed(p)) {
// Do stuff...
}
问题是前者在代码的上下文中更具可读性,所以如果我不知道结果会是什么,我有点不愿意改变它。
一个比另一个更有效吗?或者Java编译器是否足够智能以自动优化这样的事情?
答案 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计算每个方法的时间成本,然后你去了