If vs. Switch Speed
由于编译器优化,switch语句通常比等效if-else if语句(如本文中所述)更快。
这种优化实际上是如何工作的?有人能解释清楚吗?
编译器可以在适当的地方构建跳转表。例如,当您使用反射镜查看生成的代码时,您将看到对于字符串上的巨大开关,编译器将实际生成使用哈希表来调度这些代码的代码。哈希表使用字符串作为键,并将
这比许多链接的
康拉德是对的。在打开整数的连续范围的情况下(例如,在这里您有0,1,2..案例n),编译器可以做得更好,因为它甚至不需要构建哈希表;它只存储一个函数指针数组,因此可以在恒定时间内加载其跳转目标。
这是一个轻微的简化,因为通常任何现代编译器都会遇到一个
总之,康拉德答案的一个扩展是编译器可以生成一个跳转表,但这不一定保证(也不可取)。由于各种原因,跳转表对现代处理器上的分支预测器做了坏事,而表本身也做了坏事来缓存行为,例如。
1 | switch(a) { case 0: ...; break; case 1: ...; break; } |
如果编译器真的为此生成了一个跳转表,那么由于跳转表破坏了分支预测,替代的
正如康拉德所说,编译器可以构建一个跳转表。
在C++中,它之所以可以是因为交换机的限制。
- 比较项必须转换为int。
- case labl必须是常量。
switch/case语句通常速度更快,深度为1级,但当您开始进入2个或更多级别时,switch/case语句开始占用的时间是嵌套if/else语句的2-3倍。
本文进行了一些速度比较,突出了嵌套此类语句时的速度差异。
例如,根据他们的测试,示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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语句的一半时间内完成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 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和switch的情况下,no-match值都是21。编译器应该能够进行抽象,知道应该始终运行哪个语句,并且CPU应该能够正确地进行分支预测。
更有趣的是,在我看来,并非每一个案例都会破裂,但这可能不是实验的范围。
if-over-case的唯一优点是当第一个case的出现频率显著增加时。
不确定阈值的确切位置,但是我使用case语法,除非第一个"几乎总是"通过第一个测试。