我有一个可疑的编码实践.
当我需要遍历计数限制不足的项目的小列表时32000
,我使用的Int16
是我的i变量类型而不是Integer
.我这样做是因为我认为使用它Int16
比完全吹制效率更高Integer
.
我错了吗?使用Int16
vs与Integer
?之间没有有效的性能差异吗?我应该停止使用Int16
并坚持Integer
我的所有计数/迭代需求吗?
当按索引循环遍历数组或集合时,您几乎应该始终使用Int32
或Int64
(并且,不,您不会通过使用UInt32
或获得信用UInt64
).
效率较低的最明显的原因是在BCL中找到的所有数组和集合索引都采用Int32
s,因此在尝试使用s作为索引的代码中总是会发生隐式转换Int16
.
的不太明显原因(以及阵列采取的原因Int32
作为指标)是,CIL说明书说,所有的操作栈的值是任一 Int32
或Int64
.每次任一负荷或值存储到任何其他整数型(Byte
,SByte
,UInt16
,Int16
,UInt32
,或UInt64
),有涉及的隐式转换的操作.无符号类型没有加载的惩罚,但是为了存储该值,这相当于截断和可能的溢出检查.对于签名类型,每个加载符号都会扩展,并且每个商店都会签名折叠(并且可能会进行溢出检查).
这对你最有害的地方是循环本身,而不是数组访问.例如,看看这个看似无辜的循环:
for (short i = 0; i < 32000; i++) { ... }
看起来不错吧?不!您基本上可以忽略initial(short i = 0
),因为它只发生一次,但compare(i<32000
)和incrementing(i++
)部分发生了32000次.这里有一些pesudo代码,用于处理机器级别的内容:
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和你
根据以下参考,运行时优化Int32的性能,并为计数器和其他频繁访问的操作推荐它们.
从书中:MCTS Self-Paced Training Kit(考试70-536):Microsoft®.NETFramework 2.0-应用程序开发基础
第1章:"框架基础"
第1课:"使用值类型"
最佳实践:使用内置类型优化性能
运行时优化了32位整数类型(Int32和UInt32)的性能,因此将这些类型用于计数器和其他经常访问的整数变量.
对于浮点运算,Double是最有效的类型,因为这些操作是由硬件优化的.
此外,同一节中的表1-1列出了每种类型的推荐用途.与此讨论相关:
Int16 - 互操作和其他专门用途
Int32 - 整数和计数器
Int64 - 大整数
Int16实际上可能效率较低,因为用于字访问的x86指令比用于双字访问的指令占用更多空间.这取决于JIT的作用.但无论如何,当在迭代中用作变量时,几乎肯定不会更有效.
反之亦然.
32(或64)位整数比int16快.通常,本机数据类型是最快的.
如果你想让你的数据结构尽可能精简,那么Int16很不错.这节省了空间并可以提高性能.