C# 在多维数组和单个数组之间存储数据的最有效方式是什么?
基本上,我不确定如何存储3D数据结构以实现尽可能快的访问,因为我不确定在多维阵列的引擎盖下发生了什么 注意:数组每次都是一个恒定的已知大小,每个元素正好是16位 选项一是使用多维数组C# 在多维数组和单个数组之间存储数据的最有效方式是什么?,c#,arrays,multidimensional-array,unity3d,jagged-arrays,C#,Arrays,Multidimensional Array,Unity3d,Jagged Arrays,基本上,我不确定如何存储3D数据结构以实现尽可能快的访问,因为我不确定在多维阵列的引擎盖下发生了什么 注意:数组每次都是一个恒定的已知大小,每个元素正好是16位 选项一是使用多维数组data[16,16,16],只需通过data[x,y,z]访问即可。选项二是使用一维数组data[16*16*16]并通过data[x+(y*16)+(z*16*16)]访问 由于每个元素应该只有16位长,我怀疑多维数组会在内部以每个元素至少32位的速度存储大量对其他数组的引用,这是一个很大的内存浪费。然而,我担心
data[16,16,16]
,只需通过data[x,y,z]
访问即可。选项二是使用一维数组data[16*16*16]
并通过data[x+(y*16)+(z*16*16)]
访问
由于每个元素应该只有16位长,我怀疑多维数组会在内部以每个元素至少32位的速度存储大量对其他数组的引用,这是一个很大的内存浪费。然而,我担心它可能比每次运行选项2中指定的等式要快,而速度是这个项目的关键
那么,有谁能告诉我,与内存消耗的差异相比,速度可能会有多大?我会投票支持单维数组,它应该工作得更快。基本上,您可以编写一些测试,执行最常见的任务并测量所花费的时间。
另外,如果数组大小为2^n,则使用左移位运算而不是乘法来访问元素位置的速度要快得多。我认为值得指出的是,如果您的数组大小实际上都是16,则可以更高效地从(x,y,z)计算数组的索引:
int index = x | y << 4 | z << 8;
如果是这种情况,那么我建议使用一维数组,因为它几乎肯定会更快
请注意,JIT编译器完全有可能执行这种优化(假设乘法是按照您的OP硬编码的),但这是值得显式执行的
我说一维数组会更快的原因是
这就是说,您应该仔细计时,看看什么是真正最快的
正如Eric Lippert所说:.C#将多维数组存储为单个内存块,因此它们编译成几乎相同的东西。(一个区别是有三组边界需要检查)
也就是说,arr[x,y,z]
几乎等同于arr[x+y*ny+z*nz*ny]
,通常具有类似的性能特征
然而,确切的性能将取决于内存访问模式,以及这如何影响缓存一致性(至少对于大量数据而言)。您可能会发现,如果能够更好地将当前使用的数据保存在处理器缓存中,则x
、然后y
然后z
上的嵌套循环可能比按不同顺序执行循环快或慢
这在很大程度上取决于精确的算法,因此不可能给出对所有算法都正确的答案
与C++或C++相比,任何速度降低的另一个原因是边界检查,这在一维数组的情况下仍然是需要的。然而,这些通常(但并非总是)会自动删除
- 用
编写算法的原始版本李>arr[x,y,z]
- 如果速度够快,你可以停下来李>
- 另外,对算法进行概要分析,以检查问题实际上是数组访问,分析内存访问模式等等
x=index&0xF
,y=index&0xF0
,和z=index&0xF00
。downvoter:请告诉我们答案有什么问题?这将非常有用。不过,只有按顺序访问一维数组时,它才会更快,不是吗?如果你是根据已知的坐标进行查找,这两个函数应该执行相同的操作。@Luaan你读过我发布的关于缺少一些编译器优化的链接吗?是的,没错。提到的缺失优化是将计算的一部分提升到内部循环之外,这意味着大量不必要的乘法。因此,如果您试图访问阵列中的一个特定位置,那么这两个位置应该执行相同的操作。唯一没有的情况是当你在一行中的“列”上循环时-行偏移量被反复计算。。。至少我是这样理解分析的。这不完全是真的——请看我之前的链接(例如:@MatthewWatson),正如我所说,“精确的算法将影响优化者是否能够删除边界检查”@MatthewWatson公平。编辑。谢谢,我会尝试两种方法,看看哪种方法更快。我原以为两者之间会有更明显的区别。
int x = index & 0xf;
int y = (index >> 4) & 0xf;
int z = (index >> 8) & 0xf;