.Net switch 语句是散列还是索引? [英] Are .Net switch statements hashed or indexed?

查看:14
本文介绍了.Net switch 语句是散列还是索引?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

.Net 4(或任何先前版本)是否对基于字符串的较长 switch 语句执行任何类型的优化?

Does .Net 4 (or any prior version) perform any sort of optimization on longer switch statements based on strings?

我正在解决一个潜在的性能瓶颈,因为一些长的 switch 语句在案例中寻找匹配的字符串,我一直假设这些是在线性时间(或接近线性,即不使用索引来快速搜索)找到匹配的字符串).但这似乎是.Net可以优化的一个明显领域,所以我想我会检查是否是这种情况.

I'm working around a potential performance bottleneck due to some long switch statements looking for matching strings in the cases, and I've always assumed these are searched in linear time (or near linear, i.e. not using an index to quickly find the matching string). But this seems like an obvious area that .Net could optimize, so thought I'd check if this is the case or not.

这是我最近提出的一个衍生问题:indexed switch statement,或者相等的?.net, C#

This is a derivative question from my recent one: indexed switch statement, or equivalent? .net, C#

推荐答案

编译如下代码.

public static int Main(string[] args)
{
    switch (args[0])
    {
        case "x": return 1;
        case "y": return 2;
        case "z": return 3;
    }
    return 0;
}

现在使用 ReflectorILDASM 检查 C# 编译器生成的 IL.继续添加case语句,反编译观察结果.

Now use Reflector or ILDASM to examine the IL the C# compiler generates. Keep adding case statements and decompiling and observe the result.

  • 如果 case 语句的数量很少,则编译器会发出顺序相等比较.
  • 如果 case 语句的数量很大,那么编译器会发出 Dictionary 查找.

我使用的是 C# 3.0 编译器,我观察到策略在 7 个 case 语句处发生了变化.我怀疑你会看到与 C# 4.0 和其他类似的东西.

I was using the C# 3.0 compiler and I observed that the strategy changes at 7 case statements. I suspect you will see something similiar with C# 4.0 and others.

更新:

我应该指出,您将在 IL 输出中看到对 Dictionary.Add 的调用,它正在构建字典以供以后使用.不要被愚弄以为每次都会发生这种情况.编译器实际上正在生成一个单独的静态类并对其进行内联静态初始化.请特别注意 L_0026 处的说明.如果类已经初始化,那么分支将跳过 Add 调用.

I should point that you will see calls to Dictionary.Add in the IL output where it is building up the dictionary for later use. Do not be fooled into thinking this happens everytime. The compiler is actually generating a separate static class and doing an inline static initialization of it. Pay particular attention to the instruction at L_0026. If the class is already initialized then the branch will skip over the Add calls.

L_0021: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32> <PrivateImplementationDetails>{816396DD-F271-4C12-83D0-CC9C9CD67AD6}::$$method0x6000001-1
L_0026: brtrue.s L_0089
L_0028: ldc.i4.7 
L_0029: newobj instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::.ctor(int32)
L_002e: dup 
L_002f: ldstr "x"
L_0034: ldc.i4.0 
L_0035: call instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
L_003a: dup 
L_003b: ldstr "y"
L_0040: ldc.i4.1 
L_0041: call instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
L_0046: dup 
L_0047: ldstr "z"
L_004c: ldc.i4.2 
L_004d: call instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)

另外,请注意字典实际上包含从原始字符串到整数的映射.这个整数用于在 IL 中制定一个单独的开关.

Also, notice that the dictionary actually contains a map from the original string to an integer. This integer is used to formulate a separate switch in IL.

L_0089: volatile. 
L_008b: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32> <PrivateImplementationDetails>{816396DD-F271-4C12-83D0-CC9C9CD67AD6}::$$method0x6000001-1
L_0090: ldloc.2 
L_0091: ldloca.s CS$0$0002
L_0093: call instance bool [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::TryGetValue(!0, !1&)
L_0098: brfalse.s L_00da
L_009a: ldloc.3 
L_009b: switch (L_00be, L_00c2, L_00c6, L_00ca, L_00ce, L_00d2, L_00d6)
L_00bc: br.s L_00da
L_00be: ldc.i4.1 
L_00bf: stloc.1 
L_00c0: br.s L_00de
L_00c2: ldc.i4.2 
L_00c3: stloc.1 
L_00c4: br.s L_00de
L_00c6: ldc.i4.3 

更新 2:

对于它的价值,VB.NET 似乎没有对其 Select 构造进行同样的优化.

For what it is worth VB.NET does not seem to have this same optimization for its Select construct.

这篇关于.Net switch 语句是散列还是索引?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆