【发布时间】:2010-10-01 11:57:30
【问题描述】:
由于编译器优化,Switch 语句通常比等效的 if-else-if 语句(例如,在此 article 中描述的)更快。
这种优化实际上是如何工作的?谁有好的解释?
【问题讨论】:
标签: c# performance switch-statement if-statement
由于编译器优化,Switch 语句通常比等效的 if-else-if 语句(例如,在此 article 中描述的)更快。
这种优化实际上是如何工作的?谁有好的解释?
【问题讨论】:
标签: c# performance switch-statement if-statement
编译器可以在适用的情况下构建跳转表。例如,当您使用反射器查看生成的代码时,您会看到对于字符串上的巨大开关,编译器实际上会生成使用哈希表来调度这些的代码。哈希表使用字符串作为键,并将case 代码作为值。
与许多链接的if 测试相比,这具有更好的运行时间,并且实际上即使对于相对较少的字符串也更快。
【讨论】:
这是一个轻微的简化,因为通常任何现代编译器都会遇到if..else if .. 序列,该序列可以被人轻松转换为 switch 语句,编译器也会这样做。但只是为了增加额外的乐趣,编译器不受语法限制,因此可以在内部生成类似“switch”的语句,其中包含范围、单个目标等的混合——并且他们可以(并且可以)为 switch 和 if 执行此操作。 .else 语句。
Anyhoo,Konrad 回答的一个扩展是编译器可能会生成一个跳转表,但这不一定能保证(也不可取)。由于多种原因,跳转表对现代处理器上的分支预测器有不良影响,而表本身对缓存行为也有不良影响,例如。
switch(a) { case 0: ...; break; case 1: ...; break; }
如果编译器实际上为此生成了一个跳转表,则可能会比替代的if..else if.. 样式代码慢,因为跳转表会破坏分支预测。
【讨论】:
不匹配的统计数据可能不好。
如果您实际下载源代码,则在 if 和 switch 情况下,不匹配值已知为 21。编译器应该能够抽象出来,知道应该始终运行哪个语句,并且 CPU 应该能够正确地进行分支预测。
在我看来,更有趣的情况是并非所有情况都失败,但这可能不是实验的范围。
【讨论】:
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 语句运行时间的 一半 内完成:
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 构造?
【讨论】:
if over 情况的唯一优点是当第一种情况的出现频率显着增加时。
不确定阈值的确切位置,但我使用 case 语法,除非第一个“几乎总是”通过第一个测试。
【讨论】: