Java 中的布尔表达式优化
考虑 Java 中的以下方法:
public static boolean expensiveComputation() {
for (int i = 0; i < Integer.MAX_VALUE; ++i);
return false;
}
以及以下主要方法:
public static void main(String[] args) {
boolean b = false;
if (expensiveComputation() && b) {
}
}
逻辑连接(与 && 相同)是 交换运算。那么为什么编译器不将 if 语句代码优化为等效的:
if (b && expensiveComputation()) {
}
它具有 使用短路评估的好处?
此外,编译器是否尝试进行其他逻辑简化或布尔值排列以生成更快的代码?如果没有,为什么?当然有些优化会很困难,但我的例子并不简单?调用方法应该总是比读取布尔值慢,对吧?
先感谢您。
Consider the following method in Java:
public static boolean expensiveComputation() {
for (int i = 0; i < Integer.MAX_VALUE; ++i);
return false;
}
And the following main method:
public static void main(String[] args) {
boolean b = false;
if (expensiveComputation() && b) {
}
}
Logical conjunction (same as &&) is a commutative operation. So why the compiler doesn't optimize the if-statement code to the equivalent:
if (b && expensiveComputation()) {
}
which has the benefits of using short-circuit evaluation?
Moreover, does the compiler try to make other logic simplifications or permutation of booleans in order to generate faster code? If not, why? Surely some optimizations would be very difficult, but my example isn't simple? Calling a method should always be slower than reading a boolean, right?
Thank you in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
它不会这样做,因为昂贵的计算()可能会产生改变程序状态的副作用。这意味着布尔语句中表达式的求值顺序(expenseComputation() 和 b)很重要。您不希望编译器将错误优化到已编译的程序中,对吗?
例如,如果代码是这样的
,如果编译器执行了您的优化,那么
//do stuff
就会在您通过查看代码不期望它运行时运行(因为b,本来是真的,首先被评估)。It doesn't do that because expensiveComputation() may have side effects which change the state of the program. This means that the order in which the expressions in the boolean statements are evaluated (expensiveComputation() and b) matters. You wouldn't want the compiler optimizing a bug into your compiled program, would you?
For example, what if the code was like this
Here, if the compiler performed your optimization, then the
//do stuff
would run when you wouldn't expect it to by looking at the code (because the b, which is originally true, is evaluated first).因为
expenseComputation()
可能有副作用。由于 Java 的目标不是成为一种纯功能语言,因此它并不禁止程序员编写具有副作用的方法。因此,编译器分析函数纯度可能没有太多价值。然后,像您所假设的优化在实践中不太可能非常有价值,因为通常需要执行
expenseComputation()
才能获得副作用。当然,对于程序员来说,如果他们预计 b 为 false 并且明确希望避免昂贵的计算,则很容易将 b 放在第一位。
Because
expensiveComputation()
may have side-effects.Since Java doesn't aim to be a functionally pure language, it doesn't inhibit programmers from writing methods that have side-effects. Thus there probably isn't a lot of value in the compiler analyzing for functional purity. And then, optimizations like you posit are unlikely to be very valuable in practice, as
expensiveComputation()
would usually be required to executed anyway, to get the side effects.Of course, for a programmer, it's easy to put the
b
first if they expect it to be false and explicitly want to avoid the expensive computation.实际上,有些编译器可以像您建议的那样优化程序,它只需确保该函数没有副作用即可。 GCC 有一个编译器指令,您可以用它来注释函数以表明它没有副作用,然后编译器可以在优化时使用它。 Java可能有类似的东西。
一个经典的例子是
其被优化为
由 GCC 提供,优化级别为 2,至少在我的机器上是这样。
Actually, some compilers can optimise programs like the one you suggested, it just has to make sure that the function has no side-effects. GCC has a compiler directive you can annotate a function with to show that it has no side-effects, which the compiler may then use when optimizing. Java may have something similar.
A classic example is
which gets optimized to
by GCC with optimization level 2, at least on my machine.
如果您足够频繁地运行代码,编译器将对此进行优化,可能是通过内联方法并简化生成的布尔表达式(但很可能不是通过重新排序 && 的参数)。
您可以通过对该代码重复进行一百万次迭代的循环进行计时来对此进行基准测试。第一次或两次迭代比下面的慢得多。
The compiler will optimize this if you run the code often enough, probably by inlining the method and simplifying the resulting boolean expression (but most likely not by reordering the arguments of &&).
You can benchmark this by timing a loop of say a million iterations of this code repeatedly. The first iteration or two are much slower than the following.
我使用的 java 版本优化了表达式
a && 中的 a b
但不与 b 一起使用。即如果 a 为假,则不会评估 b,但如果 b 为假,则不会执行此操作。
当我在网站表单中实现验证时,我发现了这一点:我创建了消息,以一系列布尔方法在网页上显示。
我预计页面中输入错误的字段会突出显示,但由于 Java 的速度破解,代码只会执行到发现第一个错误字段为止。之后,Java 一定会想到“假&&任何东西总是假的”之类的东西,并跳过了剩余的验证方法。
我想,作为对你的问题的直接回答,如果你进行这样的优化,你的程序可能会运行得更慢。然而,其他人的程序将完全崩溃,因为他们假设了非优化行为,例如其他答案中提到的副作用。
不幸的是,自动化智能决策很困难,尤其是使用命令式语言(C、C++、Java、Python,...即普通语言)。
The version of java I am using optimises a in an expression
a && b
but not with b.i.e. If a is false, b does not get evaluated but if b was false it did not do this.
I found this out when I was implementing validation in a website form: I created messages to display on the web-page in a series of boolean methods.
I expected of the fields in the page which were incorrectly entered to become highlighted but, because of Java's speed-hack, the code was only executed until the first incorrect field was discovered. After that, Java must have thought something like "false && anything is always false" and skipped the remaining validation methods.
I suppose, as a direct answer to your question, if you make optimisations like this, your program may run slower than it could. However, someone else's program will completely break because they have assumed the non-optimised behaviour like the side effect thing mentioned in other answers.
Unfortunately, it's difficult to automate intelligent decisions, especially with imperative languages (C, C++, Java, Python,... i.e the normal languages).