114

由于编译器优化,switch 语句通常比等效的 if-else-if 语句(如本文所述)更快。

这种优化实际上是如何工作的?有人有很好的解释吗?

4

5 回答 5

190

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

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

于 2009-01-14T23:16:04.977 回答
15

这是一个轻微的简化,因为通常任何现代编译器都会遇到一个if..else if ..可以被人轻松转换为 switch 语句的序列,编译器也会这样做。但只是为了增加额外的乐趣,编译器不受语法限制,因此可以在内部生成类似“switch”的语句,这些语句混合了范围、单个目标等——他们可以(并且可以)为 switch 和 if 执行此操作。 .else 语句。

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

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

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

于 2009-01-14T23:56:28.283 回答
4

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

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

更有趣的情况是,在我看来,并非所有情况都破裂,但这可能不是实验的范围。

于 2009-01-14T23:42:57.077 回答
4

switch/case 语句通常可能更快 1 级深度,但是当您开始进入 2 级或更多时,switch/case 语句开始花费的时间是嵌套 if/else 语句的 2-3 倍。

本文有一些速度比较,突出了嵌套此类语句时的速度差异。

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

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 语句的一半时间内完成:

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 构造?

于 2014-07-27T02:54:56.923 回答
0

if over case 的唯一优点是当第一个 case 的出现频率显着增加时。

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

于 2018-04-06T16:31:05.747 回答