2010-05-12 55 views
17

让说我有一个switch语句如下Switch语句中的case顺序是否可以改变性能?

switch(alphabet) { 

    case "f": 
     //do something 
     break; 

    case "c": 
     //do something 
     break; 

    case "a": 
     //do something 
     break; 

    case "e": 
     //do something 
     break; 

} 

现在假设我知道有Alphabet e的频率最高,接着分别用A,C和F。所以,我只是调整了case语句顺序,使他们如下:

switch(alphabet) { 

    case "e": 
     //do something 
     break; 

    case "a": 
     //do something 
     break; 

    case "c": 
     //do something 
     break; 

    case "f": 
     //do something 
     break; 
} 

将在第二switch声明比第switch声明更快?如果是的话,并且如果在我的程序中,我需要多次称这个switch声明,这是否会有实质性的改进?或者如果不是,我怎样才能使用我的频率知识来提高性能?

+3

难道你不应该只用最清晰的方式写出你知道的方法吗?用真实世界的场景描述并优化你需要的地方? – 2010-05-12 03:55:06

回答

20

不是你应该关心的。这当然不是可以预测的。

对于字符串大小写标签,编译器实际上使用内部散列表,该表将字符串映射到跳转表中的索引。所以操作实际上是O(1) - 独立于标签的数量。

对于整数标签,我相信生成的实际代码取决于标签的数量以及数字是否连续(或“几乎”连续)。如果它们是连续的(1,2,3,4,...),那么它们将被转换成跳转表。如果它们有很多,那么将使用Hashtable +跳转表(就像字符串一样)。如果只有少数标签,并且他们不是立即转换成跳转表的表,只有将被转换为一系列if..then..else语句。

但是,一般来说,您应该编写代码,以便可以读取它,而不是编译器能够生成“更快”的代码。

(注意我上面描述的是C#编译器的内部工作原理的实现细节:你不应该依赖于它总是那样工作 - 事实上,它甚至可能没有工作完全一样现在 ,但至少这是一般的想法)。

+0

+1:正是我要说的。这些被实现为GOTO(检查反射器来验证)。这是O(1) - 你真的不应该担心在这一点上优化... – Khanzor 2010-05-12 03:48:45

+2

什么是所有的-1? – 2010-05-12 03:48:49

+3

+1。如果perf是真的**问题,请考虑使用离金属更近的语言。 – 2010-05-12 04:00:39

-1

我认为开关盒的做法是从上到下循环所有的情况来找到一些匹配。如果匹配,就停在那里。

因此,如果您对频率情况进​​行优先级排序进行更改,答案是肯定的,它可以帮助以某种方式提高性能。但我相信它不会有太大的帮助。

1

它们对于相对较小的一组值具有相同的性能。我试过之前检查过C程序的汇编代码,编译器会在switch语句中的所有值中创建一个跳转表。

但是,如果案例值太多,那么他们将退化为ifelse if是安全的,因此将您的案例'E'置于顶端肯定会加快速度。

在C#中它也是applicable,C#还为小集合的switch语句生成一个跳转表,虽然只是为了相邻的值。所以它是O(1),即使第一个值不匹配也没有多个测试。

2

这取决于编译器如何实现switch语句。

首先,您不能任意排列顺序;如果您有一个类似C语言(C,C++,C#,Java,...)的块 ,并且该案例块不是 以break结尾,则不能重新排列案例,因为缺少 中断意味着编译器必须实现对下一个案例的贯通。 如果我们忽略这种特殊情况,可以对其余的情况进行排列。

如果案例数量很少,编译器可以通过一系列比较来实施案例测试 。如果案例数量适中,它可以构造一个平衡二叉树。如果案例数量很大,大多数 编译器在开关值上实现索引分支,如果它是从密集集合 。如果案例值集中的部分密集,并且部分不是,则编译器可以使用二叉树 将案例分成组以选择密集和密集内的索引跳转。 (实际上,编译器在技术上可以做任何将控制权交给适当情况的控制权,但大多数情况下它是以上情况之一)。

根据编译器 如何实现开关,您可以看到订单可能很重要,也可能不重要。对于大多数优秀的编译器来说,它并不重要。

+1

为了清楚起见,问题标记为C#,并且C#不支持在第一段中描述的情况(此情况下以“break”或“return”结尾)。 – Dusty 2014-05-12 14:04:51

+0

有趣。所以人们不必要地在C#中编写“break”(例如参见OP的例子)。真的不会真正改变我的答案。 – 2014-05-12 15:11:19

+0

不,C#在这个问题上有点冗长,你必须明确地终止大小写块; 'break'(或'return')是必需的(大概是为了防止未来实现的突破情况成为突破性变化)。我同意,你的答案仍然是正确和有用的。 – Dusty 2014-05-12 17:58:41

相关问题