我想实现一个快速散列函数,它将使用int
数据类型并依赖整数溢出。MSDN 说,为了保证溢出不会触发异常,我必须unchecked
为该代码使用块。
假设我只将那个计算包围在一个unchecked
块中。我的代码会因此有任何性能或可移植性问题吗?
我想实现一个快速散列函数,它将使用int
数据类型并依赖整数溢出。MSDN 说,为了保证溢出不会触发异常,我必须unchecked
为该代码使用块。
假设我只将那个计算包围在一个unchecked
块中。我的代码会因此有任何性能或可移植性问题吗?
选中只添加一个流程指令:
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
}
通常,您可以期望未经检查的算术会稍微快一些,但几乎不值得向您提出相反的问题(即“使用检查会损害我的表现吗?”)。
Checked 和 unchecked 只是意味着关于如何处理 , 和 和 等运算符的规则略有不同+
,*
您-
应该使用适合手头情况的规则。
在这种情况下,您肯定想要取消选中,因此您应该在代码中说明这一点。这实际上增加了可移植性,因为无论使用什么编译器开关,您都将拥有相同的行为。
从技术上讲,只有checked
块应该变慢。所以我不认为一个unchecked
块(一个框架必须做更少检查的块)会变慢。它不是上下文切换或类似的东西。JIT 根本不会发出检查上溢/下溢的指令。现在,很明显,如果有人创建了一个“特殊”处理器,其中必须模拟溢出并在其上移植 Mono,或者溢出导致与 Intel 处理器不同的结果,则unchecked
块会更慢(因为 JIT 必须“模拟”它)。但请注意,.NET 的基本类型是在ECMA标准中定义的。例如,有符号整数必须基于二补码,并且它们的大小必须为 8、16、32、64 位。“奇怪”没有太多空间
我创建了两种方法,一种由 包裹,checked
另一种由unchecked
. 通过查看 IL,只有一个区别是mul
运算(执行乘法运算),mul.ovf
生成检查和未检查 - mul
。
总而言之,我相信单个 CPU 操作的差异不会对性能产生任何影响,唯一的区别是在使用溢出的情况下checked
- 在这种情况下会生成溢出异常,这显然会减慢执行速度。
以下 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 ...
未选中():
// 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(...)