我想实现一个使用int
数据类型并依赖整数溢出的快速哈希函数。 MSDN说,为了保证溢出不会触发异常,我必须为该代码使用unchecked
块。
假设我仅在unchecked
块中包围该计算。我的代码会因此而出现任何性能或可移植性问题吗?
答案 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,这显然会减慢执行。
以下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(...)