题
我有一个包含两个条件的 if 语句(由 OR 运算符分隔),其中一个条件涵盖了 +70% 的情况,并且处理/执行的时间比第二个条件少得多,因此为了速度,我只想要如果第一个条件的计算结果为 false,则要处理第二个条件。
如果我对条件进行排序,以便第一个条件(更快的条件)首先出现在 if 语句中 - 在满足此条件并评估为 true 的情况下,是否会处理第二个条件?
if ( (condition1) | (condition2) ){
// do this
}
或者我是否需要嵌套两个 if 语句,以便仅在第一个条件的计算结果为 false 时检查第二个条件?
if (condition1){
// do this
}else if (condition2){
// do this
}
我正在使用 PHP,但是,我认为这可能与语言无关。
解决方案
对于 C、C++、C#、Java 和其他 .NET 语言,布尔表达式经过优化,以便一旦已知足够的信息,就不再评估其他任何内容。
混淆代码的一个老技巧是使用它来创建 if 语句,例如:
a || b();
如果“a”为真,则“b()”永远不会被求值,因此我们可以将其重写为:
if(!a)
b();
类似地:
a && b();
会成为
if(a)
b();
请注意 这仅对||有效和&&操作员。两个操作员| &&是位或分别,并且分别是“优化”的。
编辑:正如其他人所提到的,尝试使用短路逻辑来优化代码很少会花时间。
首先要清晰,因为它更容易阅读和理解。另外,如果你试图变得太聪明,对术语的简单重新排序可能会导致毫无明显原因的截然不同的行为。
其次,进行优化,但只能在计时和分析之后进行。太多的开发人员在没有进行分析的情况下进行了过早的优化。大多数时候它是完全没用的。
其他提示
几乎每种语言都会进行短路评估。这意味着只有在绝对必要时才会评估第二个条件。为了实现这一点,大多数语言使用双管道 ||,而不是单管道 |。
在 C、C++ 和 Java 中,语句:
if (condition1 | condition2) {
...
}
每次都会评估这两个条件,并且仅当整个表达式为真时才为真。
该声明:
if (condition1 || condition2) {
...
}
会评价 condition2
除非 condition1
是假的。如果 condition2 是一个函数或另一个具有副作用的表达式,则差异很显着。
但是,两者之间没有区别 ||
案例和 if
/else
案件。
我最近看到了很多此类问题——n级优化。
我认为在某些情况下这是有道理的:
- 计算条件2不是常数时间运算
- 您提出的要求严格出于教育目的——您想了解该语言是如何工作的,而不是为了节省 3us。
在其他情况下,担心迭代或检查条件的“最快”方式是愚蠢的。不要编写需要数百万次试验才能看到任何可记录(但微不足道)差异的测试,而是关注清晰度。
当其他人(可能是你!)在一个月或一年内拿起这段代码时,最重要的是清晰度。
在这种情况下,您的第一个示例更短、更清晰,并且不需要您重复。
根据 本文 PHP 进行短路评估,这意味着如果满足第一个条件,则甚至不会评估第二个条件。测试也很容易(来自文章):
<?php
/* ch06ex07 – shows no output because of short circuit evaluation */
if (true || $intVal = 5) // short circuits after true
{
echo $intVal; // will be empty because the assignment never took place
}
?>
短路并不是为了优化。它的主要目的是避免调用无法工作的代码,但会产生可读的测试。例子:
if (i < array.size() && array[i]==foo) ...
请注意,如果 i 超出范围,则 array[i] 很可能会发生访问冲突并使程序崩溃。所以这个程序肯定是依赖于短路评估!
我相信这就是以这种方式编写表达式的原因,而不是优化问题。
虽然出于优化目的而使用短路通常是矫枉过正,但肯定还有其他令人信服的理由来使用它。一个这样的示例(用 C++ 编写)如下:
if( pObj != NULL && *pObj == "username" ) {
// Do something...
}
这里,依靠短路来确保 pObj
在解除引用之前已被分配。这比嵌套要简洁得多 if
声明。
由于这被标记为与语言无关,所以我会插话。至少对于 Perl,第一个选项就足够了,我对 PHP 不熟悉。它从左到右评估并在满足条件后立即退出。
在大多数经过适当优化的语言中,前者可以很好地工作。
这 |
是 PHP 中的按位运算符。这并不意味着 $a OR $b
, , 确切地。您将需要使用双管。是的,正如前面提到的,PHP 会进行短路评估。以类似的方式,如果第一个条件 &&
子句的计算结果为 false,PHP 也不计算该子句的其余部分。
VB.net 有两个美妙的表达式,称为“OrElse”和“AndAlso”
否则,它会在第一次达到 True 评估时自行短路并执行您想要的代码。
If FirstName = "Luke" OrElse FirstName = "Darth" Then
Console.Writeline "Greetings Exalted One!"
End If
AndAlso 第一次执行 False 评估时会将自身短路,并且不评估块内的代码。
If FirstName = "Luke" AndAlso LastName = "Skywalker" Then
Console.Writeline "You are the one and only."
End If
我发现这两者都有帮助。