?:操作员与。If 语句性能

?: Operator Vs. If Statement Performance

提问人:Jon 提问时间:2/14/2009 最后编辑:Wai Ha LeeJon 更新时间:1/10/2019 访问量:11410

问:

我一直在尝试优化我的代码,使其更加简洁和可读,并希望我不会因此而导致性能下降。我认为我的更改可能会减慢我的应用程序速度,但它可能只是在我的脑海中。两者之间是否存在任何性能差异:

Command.Parameters["@EMAIL"].Value = email ?? String.Empty;

Command.Parameters["@EMAIL"].Value = (email == null) ? String.Empty: email;

if (email == null)
{
    Command.Parameters["@EMAIL"].Value = String.Empty
}
else
{
    Command.Parameters["@EMAIL"].Value = email
}

我对可读性的偏好是空合并运算符,我只是不希望它影响性能。

C# .NET 性能 IF 语句 运算符

评论


答:

69赞 PhilChuang 2/14/2009 #1

恕我直言,针对可读性和理解性进行优化 - 与您在现实世界中花费的时间相比,任何运行时性能提升都可能是微乎其微的,当您在几个月后回到此代码并尝试了解您最初在做什么时。

评论

13赞 NotMe 2/14/2009
当然,请记住,很多程序员都可以阅读?:语句与常规 if 语句一样快。在某些情况下,它们甚至比使用不带大括号的 if / else 语句更清晰。
1赞 abelenky 2/14/2009
我同意。这里的许多帖子都是性能问题,询问一些无关紧要的小调整(++ 比 +=1 快吗?速度来自算法的复杂性:减少大量内存拷贝,快速搜索容器,适当地进行哈希处理。细微的调整不会影响性能。
10赞 nezroy 2/14/2009
-1:虽然 chublogga 的观点都是真实有效的,而且措辞很好,但它们并没有回答最初的问题。OP 是一个可以做出自己的架构/可读性选择的成年人,而 casperOne 的回答对于性能这个具体问题,其实是一个更有趣、更直接的答案。
1赞 PhilChuang 2/14/2009
我没有回答原来的问题,因为一开始就错了。
1赞 Ustaman Sangat 2/10/2012
如果人类能看到显而易见的东西,那么编译器就会足够聪明,可以看到这一点,这难道不是安全的吗?
7赞 Frederik Gheysels 2/14/2009 #2

我怀疑不会有任何性能差异。

除此之外,我想知道为什么在这种情况下你会担心偏爱一种说法而不是另一种说法?我的意思是:性能影响(如果有的话)将是最小的。恕我直言,这将是一种微优化,不值得付出努力。
我会选择最易读、最清晰的语句,并且不用担心性能,因为它的影响很小(在这种情况下)。

评论

1赞 Jon 2/14/2009
它最初的编写方式是一堆 if 语句,当我更改它时,程序似乎受到了一点性能影响。也许这是一个孤立的事件,但它比什么都更能激发我的兴趣。
7赞 Chris Ballance 2/14/2009 #3

在这种情况下,几乎没有明显的性能差异。

当性能差异可以忽略不计时,一切都与可读代码有关。

评论

1赞 phoog 11/25/2010
我会将其细化为“在没有显着性能差异的情况下,这完全与可读代码有关。有时,存在性能差异,有时这种差异很大,在这种情况下,代码可读性可能会退居二线。
1赞 Chris Ballance 7/27/2013
这和我说的有什么不同?
0赞 Johan Boulé 5/8/2015
@chris平衡 区别显然在于人们把重点放在哪里。
72赞 casperOne 2/14/2009 #4

您正在尝试在这里进行微优化,这通常是一个很大的禁忌。除非你有性能分析,告诉你这是一个问题,否则它甚至不值得改变。

对于一般用途,正确答案是更容易维护的。

不过,对于地狱来说,null 合并运算符的 IL 是:

L_0001: ldsfld string ConsoleApplication2.Program::myString
L_0006: dup 
L_0007: brtrue.s L_000f
L_0009: pop 
L_000a: ldsfld string [mscorlib]System.String::Empty
L_000f: stloc.0 

交换机的 IL 为:

L_0001: ldsfld string ConsoleApplication2.Program::myString
L_0006: brfalse.s L_000f
L_0008: ldsfld string ConsoleApplication2.Program::myString
L_000d: br.s L_0014
L_000f: ldsfld string [mscorlib]System.String::Empty
L_0014: stloc.0 

对于 null 合并运算符,如果值为 ,则执行 6 条语句,而使用 switch 时,将执行 4 条操作。null

对于 not 值,null 合并运算符执行 4 次操作,而不是 5 次操作。null

当然,这假设所有 IL 操作都花费相同的时间,但事实并非如此。

无论如何,希望你能看到在这种微观尺度上进行优化是如何开始很快减少回报的。

话虽如此,最终,在大多数情况下,在这种情况下最容易阅读和维护的是正确的答案。

如果你发现你这样做的规模被证明是低效的(而且这些情况很少而且相距甚远),那么你应该衡量一下哪个具有更好的性能,然后进行特定的优化。

评论

0赞 Sean Bright 2/14/2009
'L_0006: dup' - 在这里显示我自己的无知,但为什么需要在这里欺骗呢?
0赞 Sean Bright 2/14/2009
哦,我明白。如果它为非 null,则它存储在 000f 处并且不会弹出。意义。
0赞 John B 2/14/2009
字符串呢?IsNullOrEmpty()?
0赞 casperOne 2/15/2009
@SkippyFire:这将需要更多的 IL 指令,因为必须进行方法调用,并且它只会执行与上面类似的操作。
3赞 JoshBerke 3/18/2009
方法调用可能会在抖动时内联,不是吗?
18赞 Brian 2/14/2009 #5

我想我的改变可能已经放慢了 下载我的应用程序,但它可能只是 在我的脑海中。

除非你真的在衡量绩效,否则这一切都在你的脑海中和无聊的猜测中。

(不是特别挑剔你,但看到一个又一个关于性能微优化的问题(以及许多答案)不包含“度量”这个词,真是太令人失望了。

1赞 user1978134 5/11/2013 #6

这是一个机器级代码是否高效或人类可读代码的问题。 当我们让它对我们来说更具可读性时,它使机器变得复杂地解释代码,反之亦然......

2赞 user4023224 9/14/2014 #7

为了讨论...if/then/else 的运行速度与 ?: 三元运算的速度一样快,与单级 switch/case 语句一样快。

下面是 C# 代码的一些性能基准。

只有当您开始在 case 语句中深入 2-3 级时,性能才开始受到严重影响。也就是说,像这个荒谬的例子:

switch (x % 3)
    {
        case 0:
            switch (y % 3)
            {
                case 0: total += 3;
                    break;
                case 1: total += 2;
                    break;
                case 2: total += 1;
                    break;
                default: total += 0;
                    break;
            }
            break;
        case 1:
            switch (y % 3)
            {
                case 0: total += 3;
                    break;
                case 1: total += 2;
                    break;
                case 2: total += 1;
                    break;
                default: total += 0;
                    break;
            }
            break;
    case 2:
            switch (y % 3)
            {
                case 0: total += 3;
                    break;
                case 1: total += 2;
                    break;
                case 2: total += 1;
                    break;
                default: total += 0;
                    break;
            }
            break;
    default:
        switch (y % 3)
        {
            case 0: total += 3;
                break;
            case 1: total += 2;
                break;
            case 2: total += 1;
                break;
            default: total += 0;
                break;
        }
        break;
    }