如果 vs 开关速度

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

How does this optimization actually work? Does anyone have a good explanation?

73565 次浏览

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

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

The no-match stats may not be good.

如果实际下载了源代码,则在 If 和 switch 两种情况下,no match 值都为21。编译器应该能够抽象出来,知道应该在任何时候运行哪个语句,CPU 应该能够正确地进行分支预测。

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

这是一个轻微的简化作为典型的任何现代编译器,遇到一个 if..else if ..序列,可以转换成一个开关语句的人,编译器也将。但是为了增加额外的乐趣,编译器不受语法的限制,因此可以在内部生成“ switch”,比如混合了范围、单个目标等等的语句——它们可以(并且确实)为 switch 和 if 这样做。.Else 语句。

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

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

If a compiler actually generated a jump table for this it would likely be slower that the alternative if..else if.. style code because of the jump table defeating branch prediction.

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

This article has some speed comparisons highlighting the speed differences when such statements are nested.

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

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 语法,除非第一个“几乎总是”通过第一个测试。