如果与Switch Speed相对

时间:2009-01-14 23:13:28

标签: c# performance switch-statement if-statement

由于编译器优化,switch语句通常比等效的if-else-if语句更快(例如在article中描述)。

这种优化实际上如何运作?有没有人有一个很好的解释?

7 个答案:

答案 0 :(得分:176)

编译器可以在适用的情况下构建跳转表。例如,当您使用反射器查看生成的代码时,您将看到对于字符串上的大型开关,编译器实际上将生成使用哈希表来分派这些代码的代码。哈希表使用字符串作为键,并将case代码委托为值。

这比许多链式if测试具有渐近更好的运行时间,即使对于相对较少的字符串实际上也更快。

答案 1 :(得分:29)

Konrad是正确的。在切换连续的整数范围的情况下(例如,你有案例0,案例1,案例2 ..案例n),编译器可以做更好的事情,因为它甚至不需要构建哈希表;它只是存储一个函数指针数组,因此可以在恒定时间内加载其跳转目标。

答案 2 :(得分:13)

这是一种轻微的简化,因为通常任何遇到if..else if ..序列的现代编译器都可以由一个人轻易地转换为switch语句,编译器也是如此。但是为了增加额外的乐趣,编译器不受语法的限制,因此可以在内部生成具有混合范围,单个目标等的“切换”语句 - 并且它们可以(并且确实)为交换机和if执行此操作。 .else声明。

Anyhoo,对Konrad的答案的扩展是编译器可能会生成一个跳转表,但这不一定得到保证(也不可取)。由于各种原因,跳转表会对现代处理器上的分支预测器做坏事,而表本身也会对缓存行为做坏事,例如。

switch(a) { case 0: ...; break; case 1: ...; break; }

如果编译器为此实际生成了一个跳转表,那么替换if..else if..样式代码可能会慢一些,因为跳转表会破坏分支预测。

答案 3 :(得分:5)

正如Konrad所说,编译器可以构建一个Jump表。

在C ++中,原因可能是由于交换机的限制。

答案 4 :(得分:4)

不匹配的统计数据可能不太好。

如果您实际下载了源,则在if和switch的情况下,已知无匹配值为21。编译器应该能够抽象出来,知道应该始终运行哪个语句,并且CPU应该能够正确地进行分支预测。

更有趣的案例是,在我看来,并非每个案例都会破裂,但这可能不是实验的范围。

答案 5 :(得分:4)

Switch / case语句通常可以更快1级,但是当你开始进入2级或更多时,switch / case语句的开始时间是嵌套的if / else语句的2-3倍。

This article has some speed comparisons突出显示嵌套此类语句时的速度差异。

例如,根据他们的测试,示例代码如下:

if (x % 3 == 0)
            if (y % 3 == 0)
                total += 3;
            else if (y % 3 == 1)
                total += 2;
            else if (y % 3 == 2)
                total += 1;
            else
                total += 0;
        else if (x % 3 == 1)
            if (y % 3 == 0)
                total += 3;
            else if (y % 3 == 1)
                total += 2;
            else if (y % 3 == 2)
                total += 1;
            else
                total += 0;
        else if (x % 3 == 2)
            if (y % 3 == 0)
                total += 3;
            else if (y % 3 == 1)
                total += 2;
            else if (y % 3 == 2)
                total += 1;
            else
                total += 0;
        else
            if (y % 3 == 0)
                total += 3;
            else if (y % 3 == 1)
                total += 2;
            else if (y % 3 == 2)
                total += 1;
            else
                total += 0;

在等效的switch / case语句运行时 half 完成:

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;
    }

是的,这是一个基本的例子,但它说明了这一点。

所以一个结论可能是使用switch / case来处理只有一层深度的简单类型,但对于更复杂的比较和多个嵌套级别,使用经典的if / else结构?

答案 6 :(得分:0)

if over case的唯一优点是当第一种情况的出现频率明显增加时。

不确定阈值的确切位置,但我使用case语法,除非第一个“几乎总是”通过第一个测试。