使用未经检查的上下文是否会损害C#中的性能或可移植性?

时间:2011-10-20 08:08:37

标签: c# .net performance portability unchecked

我想实现一个使用int数据类型并依赖整数溢出的快速哈希函数。 MSDN说,为了保证溢出不会触发异常,我必须为该代码使用unchecked块。

假设我仅在unchecked块中包围该计算。我的代码会因此而出现任何性能或可移植性问题吗?

4 个答案:

答案 0 :(得分:8)

从技术上讲,只有checked块才会变慢。所以我不认为unchecked块(框架必须进行较少检查的块)可能会变慢。它不是上下文切换或类似的东西。 JIT根本不发出检查溢出/下溢的指令。现在,显然如果有人创建了一个“特殊”处理器,其中必须模拟溢出并在其上移植Mono,或者溢出导致与英特尔处理器不同的结果,unchecked块将更慢(因为JIT会有“模拟”它)。但请注意,.NET的基本类型是在ECMA标准中定义的。有符号的整数必须基于双补码,并且它们的大小必须是8,16,32,64位。使用36 bits integers的“奇怪”处理器没有太多空间。

答案 1 :(得分:8)

作为一项规则,您可以预期未经检查的算术会稍微快一些,但几乎不值得向您提出相反的问题(即“将使用检查会损害我的表现吗?”)。

选中和取消选中只是意味着对+*-等运营商的处理规则略有不同,您应该使用适合此案例的规则手。

在这种情况下,您肯定希望取消选中,因此您应该在代码中说明这一点。这实际上增加了可移植性,因为无论编译器开关与它一起使用,你都会有相同的行为。

答案 2 :(得分:7)

选中只添加一条处理指令:

checked
{
    int y = x * x;
05297978  mov         eax,dword ptr [ebp-10h]  
0529797B  imul        eax,dword ptr [ebp-10h]  
0529797F  jno         05297986  //if not overflow: goto 05297986
05297981  call        72A29522  //invoke exception
05297986  mov         dword ptr [ebp-14h],eax  
}

unchecked
{
    int yy = xx * xx;
0529799E  mov         eax,dword ptr [ebp-18h]  
052979A1  imul        eax,dword ptr [ebp-18h]  
052979A5  mov         dword ptr [ebp-1Ch],eax  
}

答案 3 :(得分:4)

我创建了两个方法,一个由checked包裹,另一个由unchecked包裹。通过查看IL,只有一个差异是mul操作(执行乘法运算),对于已检查的mul.ovf生成和未选中 - mul

总而言之,我认为单个CPU操作的差异不会对性能产生任何影响,唯一的区别在于使用checked溢出的情况 - 在这种情况下,将生成OverflowException,这显然会减慢执行。

MSDN:

  

以下Microsoft中间语言(MSIL)说明   抛出一个OverflowException:

     
      
  • mul.ovf。
  •   
  • ...
  •   
[Test]
public void Checked()
{
    checked
    {
        int i = int.MaxValue;
        i = i * 100;
        Debug.WriteLine(i);
    }
}

[Test]
public void UnChecked()
{
    unchecked
    {
        int i = int.MaxValue;
        i = i * 100;
        Debug.WriteLine(i);
    }            
}

然后使用ILDASM参见IL:

<强>选中():

// Code size       27 (0x1b)
  .maxstack  2
  .locals init ([0] int32 i)
  IL_0000:  nop
  IL_0001:  nop
  IL_0002:  ldc.i4     0x7fffffff
  IL_0007:  stloc.0
  IL_0008:  ldloc.0
  IL_0009:  ldc.i4.s   100
  **IL_000b:  mul.ovf** !!!
  IL_000c:  stloc.0
  IL_000d:  ldloc.0
  IL_000e:  box        [mscorlib]System.Int32
  IL_0013:  call       void [System]System.Diagnostics.Debug::WriteLine ...

<强> UNCHECKED():

  // Code size       27 (0x1b)
  .maxstack  2
  .locals init ([0] int32 i)
  IL_0000:  nop
  IL_0001:  nop
  IL_0002:  ldc.i4     0x7fffffff
  IL_0007:  stloc.0
  IL_0008:  ldloc.0
  IL_0009:  ldc.i4.s   100
  **IL_000b:  mul** !!!
  IL_000c:  stloc.0
  IL_000d:  ldloc.0
  IL_000e:  box        [mscorlib]System.Int32
  IL_0013:  call       void [System]System.Diagnostics.Debug::WriteLine(...)