我遇到了程序中的性能瓶颈,我需要在紧密的循环中数百万次访问数组中的元素。
我环顾四周,普遍的共识似乎是即使多维数组应该更快,它们的底层实现也是低效的,所以只需使用锯齿状数组。我对它进行了分析,肯定的是,锯齿状阵列的速度提高了50%。细
但是,我也尝试过手动编制索引(例如,通过执行类似这样的操作来模拟多维数组的行为:object value = array[i * 24 + j]; (where 24 is an array size)
并通过带有乘法的单维数组访问它以模拟多维数组
令人惊讶的是,对于访问而言,这也比锯齿状阵列快15%(我只关心)。这让我感到很难过,因为对于一个人来说,手动重建多维数组比使用C#的内置实现要快得多而且两个,与仅使用锯齿状/多维数组进行索引相比,获取指标所涉及的数学更为难以实现
有什么办法可以在不使用我自己的手动索引的情况下收回速度优势吗?当然可以设置或检查某种优化来模拟这种行为?为什么数组的C#实现效率低下?
答案 0 :(得分:5)
令人惊讶的是,对于访问来说,这也比锯齿状阵列快15%左右
这应该不足为奇,因为对锯齿状数组进行索引需要额外的解引用。当您编写a[i][j]
时,计算机必须执行以下操作:
i
a
的位置
a[i]
的位置(第一个取消引用)j
a[i]
的位置
j
的位置a[i]
的值(第二次取消引用)在向量中折叠2D数组时,计算机只会进行一次解除引用:
基本上,您正在交易乘法的解除引用;乘法更便宜。
此外,你可以获得内存中元素的连续性 - 这是你用锯齿状数组无法保证的。这对于对缓存命中敏感的代码非常重要。
我有什么办法可以在不使用我自己的手动索引的情况下收回速度优势吗?
使用索引方案是一种方法。您可以通过创建一个类来隐藏代码的查看者,例如,Matrix2D
公开一个带有两个索引并生成值的operator []
。这样,计算偏移量的代码将对程序的读者隐藏,因为a[i * 24 + j]
部分看起来像a[i, j]