嵌套`如果提高性能?

时间:2012-12-30 08:36:08

标签: performance optimization if-statement conditional-statements short-circuiting

如果我有这段代码:

if (isFoo() && isBar())
{
    ...
}

程序将计算第一个条件,然后计算第二个条件,然后确定是通过还是跳过下面的块。

但是,如果我像这样嵌套条件:

if (isFoo())
    if(isBar())
    {
        ...
    }

现在它检查第一个条件,如果它是假的,它不会打扰第二个条件。

如果第二个条件(作为一个函数)是一个耗时的内存昂贵的猪,它似乎更好地嵌套它。

这是真的吗?我以前从未见过这样的代码,我在第一个例子之后做了一个假设,但IMO非常有可能。

6 个答案:

答案 0 :(得分:3)

这取决于编程语言。

大多数现代/流行语言支持Short circuit evaluation,这意味着程序不会评估整个表达式,但在获得整个表达式的结果后立即停止评估(其他人已经给出了示例)。

但也有例外

我知道不支持短路评估的两种语言是Microsoft VB(6)和VB.NET。

VB6根本不支持它,所以这里嵌套If如果常见的优化技术。 此外,在表达式

If Not rs Is Nothing And Not rs.EOF

Ifrs时,不使用嵌套Nothing会导致执行错误。

VB.NET引入了两个支持短路评估的新逻辑运算符AndAlsoOrElse

标准VB.NET AndOr运算符不支持短路评估,这是新手开发人员的常见错误来源。

Optimalizations

在这两种情况下(语言支持而非短路评估),您都可以查看 表达式按更快地评估

所以代替(如果用户是女性,请检查数据库,使用偶数密钥并登录):

if (db.getUserSex() == FEMALE && userKey % 2 == 0 && userKey % 2 && isUserLogged)

使用(检查是否登录(布尔值),偶数键(算术运算符)并最后检查DB中的性别):

if (isUserLogged && userKey % 2 == 0 && db.getUserSex() == FEMALE)

答案 1 :(得分:2)

在C#/ C ++和许多其他语言中,您实际上有两个逻辑AND运算符:&&&

&运算符将评估这两个条件

&&运算符只会先评估,如果等于FALSE,则会跳过表达式的第二部分。

同样适用于逻辑OR运算符。有两个运算符:|||

|运算符将评估这两个条件

||运算符只会先评估,如果等于TRUE,则会跳过表达式的第二部分。

所以,回答你的问题,在你的例子中,你正在使用&&,它将表现为两个嵌套if

[编辑] :好的,找到使用|的例子并不容易和我个人在最短的代码比赛中使用它们))这是他们真正有用的地方(不是因为它们比&&和||更短)。还请考虑以下示例:

static bool LaunchFirstRocket()
{
    // Launching rocket if all is ok return true, or return false if we failed to launch it.
}

static bool LaunchSecondRocket()
{
    // Launching rocket if all is ok return true, or return false if we failed to launch it.
} 

static void Main(string[] args)
{
    if (LaunchFirstRocket() & LaunchSecondRocket())
    {
        Console.WriteLine("Both rockets have launched successfully!");
    }
}

这里我们将强制执行两种方法,而不管第一种方法的结果如何。如果第一次火箭失败,我们仍然想要推出第二次,这是我们的逻辑。是的,有很多很多的其他方式来编写此类代码,但这只是教育目的的一个示例。

答案 2 :(得分:1)

我相信大多数编译器会为你做这个优化。如果&&的第一个条件是假的,第二个不会被执行。

答案 3 :(得分:1)

  

程序将计算第一个条件,然后计算第二个条件,

不,不是大多数现代语言(例如C,C ++)。因为已知如果第一个条件为假,那么AND表达式的值不可能是除false之外的任何值,因此不评估第二个部分。在这两种语言中,标准明确定义了这种优化(称为“短路评估”)。

答案 4 :(得分:1)

这取决于。正如其他人所指出的那样,在使用short-circuit evaluation的编译语言(例如C和C ++)中,两个版本都可能编译为完全相同的代码。

在某些解释型语言中,例如Perl,第二个版本实际上可能比第一个版本慢,因为在输入代码块时会有很少的开销。例如,这个人工基准显示了明显的差异:

use Benchmark ':all';
my $count = shift || 10_000_000;
our ($foo, $bar, $baz) = (1, 1, 1);
timethese( $count, {
    'and'    => 'if ($foo && $bar) { $baz++; }',
    'nested' => 'if ($foo) { if ($bar) { $baz++; } }',
});

输出:

Benchmark: timing 10000000 iterations of and, nested...
       and:  2 wallclock secs ( 2.41 usr +  0.00 sys =  2.41 CPU) @ 4149377.59/s (n=10000000)
    nested:  4 wallclock secs ( 3.54 usr +  0.00 sys =  3.54 CPU) @ 2824858.76/s (n=10000000)

当然,在实践中,差异可能是完全无关紧要的,特别是与使用解释性语言开头的一般开销相比。

答案 5 :(得分:0)

所有现代语言都会使任何AND'ed条款短路。所以,在你的例子中,如果isFoo()为false,它甚至不会检查isBar(),它会退出if语句。