Switch 语句中 case 的顺序会改变性能吗?
假设我有一个如下的 switch 语句
switch(alphabet) {
case "f":
//do something
break;
case "c":
//do something
break;
case "a":
//do something
break;
case "e":
//do something
break;
}
现在假设我知道字母表 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
语句,这会是一个实质性的改进吗?或者如果没有,我如何利用我的频率知识来提高性能?
Let say I have a switch statement as below
switch(alphabet) {
case "f":
//do something
break;
case "c":
//do something
break;
case "a":
//do something
break;
case "e":
//do something
break;
}
Now suppose I know that the frequency of having Alphabet
e is highest followed by a, c and f respectively. So, I just restructured the case
statement order and made them as follows:
switch(alphabet) {
case "e":
//do something
break;
case "a":
//do something
break;
case "c":
//do something
break;
case "f":
//do something
break;
}
Will the second switch
statement be faster than the first switch
statement? If yes and if in my program I need to call this switch
statement say many times, will that be a substantial improvement? Or if not in any how can I use my frequency knowledge to improve the performance?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
没有那么多你应该担心的。这当然不是可以预测的事情。
对于字符串大小写标签,编译器实际上使用内部哈希表将字符串映射到跳转表中的索引。因此该操作实际上是 O(1) - 与标签数量无关。
对于整数标签,我相信生成的实际代码取决于标签的数量以及数字是否连续(或“几乎”连续)。如果它们是连续的(1、2、3、4...),那么它们将被转换为跳转表。如果有很多,那么将使用哈希表+跳转表(就像字符串一样)。如果只有几个标签,并且它们不是要立即转换为跳转表的表,只有then才会转换为一系列if..then..else语句。
不过,一般来说,您应该编写代码以便您可以阅读它,而不是让编译器可以生成“更快”的代码。
(请注意,我上面的描述是 C# 编译器如何内部工作的实现细节:您不应该总是依赖它那样工作——事实上,它甚至可能不完全那样工作 >现在,但至少这是总体想法)。
Not so much that you should be concerned. It's certainly not something that can be predicted.
With string case labels, the compiler actually uses an internal hash table that maps the strings to indexes in a jump-table. So the operation is actually O(1) - independent of the number of labels.
For integer labels, then I believe the actual code that is generated depends on the number of labels and whether the numbers are consecutive (or "almost" consecutive). If they're consecutive (1, 2, 3, 4, ...) then they'll just be transformed into a jump table. If there's a lot of them, then the Hashtable+jump table (like with strings) will be used. If there's only a few labels and they're not table to be immediately transformed into a jump table, only then will be transformed into a series of if..then..else statements.
In general, though, you should write code so that you can read it, not so that the compiler can produce "faster" code.
(Note my description above is an implementation detail of how the C# compiler works internally: you shouldn't rely on it always working like that -- in fact, it might not even work exactly like that now, but at least it's the general idea).
这取决于编译器如何实现 switch 语句。
首先,不能随意颠倒顺序;如果你有一个案例块
在类似 C 的语言(C、C++、C#、Java 等)中,并且该 case 块不
在中断中终止,您无法重新排列案例,因为缺少
中断意味着编译器必须实现下一种情况的失败。
如果我们忽略这种特殊情况,则可以对其余情况进行排列。
如果案例数量较少,编译器可以进行案例测试
通过一系列比较。如果案例数量不多,可以构建
来自案例的平衡二叉树。如果病例数量较多,则大多数
如果开关值来自,编译器会在开关值上实现索引分支
一个密集的集合。如果案例值集合的部分内容是密集的,并且部分内容是
不,编译器可以使用二叉树将案例分成组
选择哪个稠密集,以及稠密集中的索引跳转。
(事实上,从技术上来说,编译器可以做任何将控制权传递给
适当的情况,但最常见的是上述情况之一)。
您可以看到顺序可能重要,也可能不重要,具体取决于编译器的方式
实现开关。对于大多数优秀的编译器来说,这并不重要。
It depends on how the compiler implements the switch statement.
First, you can't arbitrarily permute the order; if you have one case block
in a C-like language (C, C++, C#, Java, ...), and that case block does not
terminate in break, you can't rearrange the cases because the absence of
the break means the compiler must implement fall-through to the next case.
If we ignore this special situation, you can permute the rest of the cases.
If the number of cases is small, the compiler may implement the case tests
by a sequences of compares. If the number of cases is modest, it may construct
a balanced binary tree from the cases. If the number of cases is large, most
compilers implement an indexed branch on the switch value if it is from
a dense set. If parts of the set of case values is dense, and parts are
not, the compiler may partition the cases into groups using a binary tree
to select which dense set, and an indexed jump within the dense set.
(In fact, the compiler may technically do anything that passes control to the
appropriate case, but most often it is one of the above).
You can see that order may matter, or it may not, depending on how the compiler
implements the switch. For most good compilers, it does not matter much.
对于相对较小的一组值,它们具有相同的性能。我之前尝试检查 C 程序的汇编代码,编译器根据 switch 语句中的所有值创建一个跳转表。
但如果 case 值太多,可以肯定它们会退化为
if
else if
,因此将 case 'E' 放在顶部肯定会加快速度。它在 C# 中也适用,C# 还会生成 switch 的跳转表具有小集合的语句,尽管仅适用于相邻值。所以它的复杂度是 O(1),即使第一个值不匹配,也不会进行多次测试。
They have the same performance for a relatively small set of values. I tried checking the assembly code of C program before, the compiler creates a jump table out of all the values you have in your switch statement.
But if the case values are too many, it's a safe bet that they will degenerate to
if
else if
, so putting your case 'E' on top would surely speed things up.It's also applicable in C#, C# also produces a jump table for switch statements with a small set, albeit for adjacent values only. So it's O(1), there's no multiple testing even if the first values doesn't match.
我认为 switch case 的做法是它会从上到下循环所有的 case 来找到一些匹配。如果匹配,则停在那里。
因此,如果您进行了更改以优先考虑频率情况,答案是肯定的,它可以在某种程度上帮助提高性能。但我相信这不会有太大帮助。
I think the way switch case do is it will loop over all the cases from top to bottom to find some match. If it matches, it stops there.
So, if you made changes to prioritize the frequency cases, the answer is yes, it can help somehow with performance. But I believe that it will not help much.