我的编码习惯有问题。
当我需要遍历计数限制低于 32000
的一小部分项目时,我使用 Int16
作为我的 i 变量类型而不是 Integer
。我这样做是因为我假设使用 Int16
比完全成熟的 Integer
更有效。
我错了吗?使用 Int16
与 Integer
之间是否没有有效的性能差异?我是否应该停止使用 Int16
并坚持使用 Integer
来满足我所有的计数/迭代需求?
最佳答案
你应该几乎总是使用Int32
或 Int64
(而且,不,在按索引遍历数组或集合时,您不会通过使用 UInt32
或 UInt64
获得积分。
它效率较低的最明显原因是在 BCL 中找到的所有数组和集合索引都采用 Int32
s,因此在尝试使用 Int16
的代码中总是会发生隐式转换。 s 作为索引。
不太明显的原因(以及数组将 Int32
作为索引的原因)是 CIL 规范规定所有操作堆栈值或者 Int32
或 Int64
.每次将值加载或存储为任何其他整数类型( Byte
、 SByte
、 UInt16
、 Int16
、 UInt32
或 UInt64
)时,都会涉及隐式转换操作。无符号类型对加载没有惩罚,但对于存储值,这相当于截断和可能的溢出检查。对于有符号类型,每个 加载符号扩展,每个存储符号折叠(并且有可能的溢出检查)。
这对您伤害最大的地方是循环本身,而不是数组访问。以这个看似无辜的循环为例:
for (short i = 0; i < 32000; i++) {
...
}
看起来不错吧?没有!您基本上可以忽略初始化(short i = 0
),因为它只发生一次,但是比较(i<32000
)和递增(i++
)部分发生了 32000 次。这里有一些关于这东西在机器级别的样子的伪代码:
Int16 i = 0;
LOOP:
Int32 temp0 = Convert_I16_To_I32(i); // !!!
if (temp0 >= 32000) goto END;
...
Int32 temp1 = Convert_I16_To_I32(i); // !!!
Int32 temp2 = temp1 + 1;
i = Convert_I32_To_I16(temp2); // !!!
goto LOOP;
END:
那里有 3 次转换,运行了 32000 次。只需使用 Int32
就可以完全避免它们。或 Int64
.
更新:正如我在评论中所说,我现在实际上已经写了一篇关于这个主题的博文,.NET Integral Data Types And You
关于c# - .NET 整数与 Int16?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/129023/