优化:switch 语句中的 case 顺序重要吗? [关闭]

Posted

技术标签:

【中文标题】优化:switch 语句中的 case 顺序重要吗? [关闭]【英文标题】:Optimization: Is the order of cases in a switch statement important? [closed] 【发布时间】:2014-06-01 20:05:38 【问题描述】:

考虑使用您选择的语言(例如,Java、C、C#...)中的 switch 语句。当然,case 语句的顺序很重要,如果有失败,但假设每个case 都有一个break,所以顺序没有语义重要性。

case 语句的顺序在考虑优化时是否重要?是按升序对案例进行排序更好,还是任何排序都没有好处?编译器可能执行的优化可能取决于cases 的顺序。由于任何编译器可能会或可能不会选择此类优化,因此我不想在这里询问特定的语言或编译器。问题是关于可能发生的事情。

【问题讨论】:

这种语言是否适用于一组特定的编程语言? 我不会欺骗这个,但这是一个可能的欺骗:***.com/questions/2815983/… 据我所知,您提到的所有语言都没有强制要求 switch 的性能行为——所以这实际上是一个关于实现的问题,而不是语言。如果你想限制你的问题,它应该是“gcc,clang,openjdk,MS CLR”之类的。 @gexicide,我认为这是一个不错的问题,但措辞方式使其过于宽泛。如果您关心优化开关的工作方式,也许您应该关心的是编译器,而不是语言。也许改写这个问题(或重新提问,看看你在这里得到的关闭/否决票的数量)以专注于这个问题 - 例如。 “案例的顺序是否会影响开关的可能编译器优化”。编译器使用了一些重要的技巧来优化开关,因此这可能是一个非常有趣但可能不太实用的问题。 我认为这是一个合理的问题,而且不是太宽泛,因为我认为从实际的角度来看,在大多数情况下都有一个正确的答案:将最常见的情况放在首位不会有任何伤害,并且可能会有所帮助,如果 switch 语句是性能接收器。不过,它看起来确实可能是 Mystical 发现的问题的欺骗。 【参考方案1】:

答案不仅取决于语言,还取决于编译器,甚至取决于您选择的编译器设置。我已经看到它在 C++ 中有所不同,具体取决于我选择的 gcc 优化设置。

这是因为编译器可能选择将 switch 语句实现为一系列测试,就像一系列 if / else if 语句一样,或者它可能选择将 switch 语句实现为跳转表。对于较早的测试,一系列测试会更快,而跳转表通常会同样快,无论顺序如何。

如果您的编译器将您的 switch 语句实现为一系列测试 - 并且不重新排序它们 - 将更有可能的情况提前放置将导致更快的代码。据我所知,将更可能的情况提前放置通常不会导致代码变慢,因此如果您的代码花费大量时间执行此 switch 语句,那么将更常见的情况提前放置也无妨。

但是,如果您没有分析过您的代码并且您不知道 switch 语句是一个性能问题,那么最好按照阅读代码的人最清楚的顺序来编写 switch 语句.

【讨论】:

另外,如果 switch case 真的非常长,以至于你开始遇到指令缓存未命中,那么即使在跳转表的情况下,把最有可能的情况放在首位也会导致加速。【参考方案2】:

从这个基准来看,它确实很重要: http://pastebin.com/rJMEunAT

第一种方法在 0.2423 滴答时结束,第二种方法在 0.1654 结束

【讨论】:

【参考方案3】:

对于禁止多个 case 子句匹配的语言,并且编译器至少进行了一些优化,几乎可以肯定,编写 case 子句的顺序不会有什么不同。

有三种流行的编译 switch 语句的方法:

硬编码二进制搜索

索引跳转表

散列跳转表

这三个都要求编译器重新排序子句。选择哪一个取决于语言、目标处理器、case 子句中的值分布以及可能的月相。

【讨论】:

以上是关于优化:switch 语句中的 case 顺序重要吗? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

switch语句里不需要必须有break吗

SWITCH语句中的case后可以是字符串吗?

switch case 语句中的分号

关于switch语句,case和default的执行顺序,

Java中String,long,byte类型可以作为switch中的表达式吗?

swtich能判断取值范围吗