-
22-07-2019 - |
题
Switch 语句通常比等效的 if-else-if 语句更快(例如在此描述的 文章)由于编译器优化。
这种优化实际上是如何运作的?有人有好的解释吗?
解决方案
,编译器可以建立跳转表适用。例如,当您使用反射来看看生成的代码,你会看到,对字符串巨大的开关,编译器将实际产生使用哈希表来调度这些代码。哈希表使用字符串作为键和委托给case
码作为值。
这具有渐进比很多链接if
测试更好的运行时,实际上更快,甚至相对弦数。
其他提示
康拉德是正确的。在对整数连续范围的切换的情况下(例如,当你有0的情况下,案例1,案例2 ..当n),编译器可以做一些事情,甚至更好,因为它甚至不需要建立一个哈希表;它简单地存储一个函数指针阵列,并且因此可以加载其跳转目标在恒定的时间。
这是一个简化的轻微如通常任何现代编译器,遇到可能平凡由人转换成switch语句,编译器将以及一个if..else if ..
序列。但是,仅仅添加额外的乐趣编译器不受语法限制,可以产生“开关”一样在内部声明,有范围的,单一的目标,等的混合 - 他们可以(做)这样做的交换机和如果。的.else语句。
安美居,延伸到康拉德的回答是,编译器可以生成跳转表,但是这并不一定保证(也不可取)。对于各种原因跳表做不好的事情,对现代处理器的分支预测,以及表本身做坏事缓存行为,如:
switch(a) { case 0: ...; break; case 1: ...; break; }
如果一个编译器实际产生的跳转表此它可能会比较慢,由于跳转表击败分支预测的替代if..else if..
样式代码。
在不匹配的统计信息可能不太好。
如果你实际下载源,无匹配值已知是21,在两个如果和开关壳体。编译器应该能够抽象掉,知道哪些语句应该在任何时候都可以运行,并且CPU应该能够预测分支正确。
更有趣的情况是,不是每一个打破的情况下,在我看来,但可能不是这个实验的范围。
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 结构?
如果超过箱子的唯一优点是当在第一种情况下的发生频度的显着增加。
不知道确切其中阈值是,但我用的情况下的语法,除非第一“几乎总是”经过第一测试。