在多维数组和单个数组之间存储数据的最有效方法是什么?
What is the most efficient way of storing data between a multi-dimension array, and a single array?
基本上我不确定如何存储 3D 数据结构以实现最快的访问速度,因为我不确定多维数组的幕后情况。
注意:数组每次都是常量和已知大小,每个元素都是 16 位。
选项一是拥有多维数组 data[16, 16, 16]
并通过 data[x, y, z]
访问 选项二是拥有一维数组 data[16 * 16 * 16]
并通过 [=13= 访问].
因为每个元素应该只有 16 位长,而且我怀疑多维数组会在内部存储大量对其他数组的引用,每个数组最少 32 位,这是很多浪费内存。但是,我担心它可能比 运行 每次都在选项二中指定的方程式更快,速度是这个项目的关键。
所以,谁能告诉我,与内存消耗的差异相比,速度的差异有多大?
我会投票给单维数组,它应该工作得更快。基本上您可以编写一些测试,执行您最常见的任务并测量花费的时间。
此外,如果您有 2^n 个数组大小,则使用左移运算而不是乘法来访问元素位置要快得多。
我认为值得指出的是,如果你的数组维度真的都是 16,那么你可以更有效地从 (x, y, z) 计算数组的索引:
int index = x | y << 4 | z << 8;
反之:
int x = index & 0xf;
int y = (index >> 4) & 0xf;
int z = (index >> 8) & 0xf;
如果是这种情况,那么我建议使用一维数组,因为它几乎肯定会更快。
请注意,JIT 编译器完全有可能执行此优化(假设根据您的 OP 对乘法进行了硬编码),但值得明确地进行。
之所以说一维数组会更快是因为the latest compiler is lacking some of the optimisations for multi-dimensional array access, as discussed in this thread.
也就是说,您应该仔细计时,看看什么才是最快的。
正如 Eric Lippert 所说:"If you want to know which horse is faster, race your horses"。
C# 将多维数组存储为单个内存块,因此它们编译成几乎相同的东西。 (一个区别是要检查三组边界)。
即arr[x,y,z]
几乎等同于 arr[x + y*ny +z*nz*ny]
,通常具有相似的性能特征。
然而,确切的性能将取决于内存访问模式,以及这如何影响缓存一致性(至少对于大量数据而言)。您可能会发现 x
然后 y
然后 z
的嵌套循环可能比以不同顺序执行循环更快或更慢,如果一个人在保留当前使用的数据方面做得更好的话在处理器缓存中。
这在很大程度上取决于具体的算法,因此不可能给出对所有算法都正确的答案。
与 C 或 C++ 相比速度降低的另一个原因是边界检查,在一维数组的情况下仍然需要边界检查。然而,这些通常(但并非总是)会自动删除。
同样,确切的算法将影响优化器是否能够删除边界检查。
您的操作步骤如下:
- 使用
arr[x,y,z]
编写算法的简单版本。
- 如果足够快,您可以停下来。
- 否则分析算法以检查问题实际上是数组访问,分析内存访问模式等。
基本上我不确定如何存储 3D 数据结构以实现最快的访问速度,因为我不确定多维数组的幕后情况。
注意:数组每次都是常量和已知大小,每个元素都是 16 位。
选项一是拥有多维数组 data[16, 16, 16]
并通过 data[x, y, z]
访问 选项二是拥有一维数组 data[16 * 16 * 16]
并通过 [=13= 访问].
因为每个元素应该只有 16 位长,而且我怀疑多维数组会在内部存储大量对其他数组的引用,每个数组最少 32 位,这是很多浪费内存。但是,我担心它可能比 运行 每次都在选项二中指定的方程式更快,速度是这个项目的关键。
所以,谁能告诉我,与内存消耗的差异相比,速度的差异有多大?
我会投票给单维数组,它应该工作得更快。基本上您可以编写一些测试,执行您最常见的任务并测量花费的时间。 此外,如果您有 2^n 个数组大小,则使用左移运算而不是乘法来访问元素位置要快得多。
我认为值得指出的是,如果你的数组维度真的都是 16,那么你可以更有效地从 (x, y, z) 计算数组的索引:
int index = x | y << 4 | z << 8;
反之:
int x = index & 0xf;
int y = (index >> 4) & 0xf;
int z = (index >> 8) & 0xf;
如果是这种情况,那么我建议使用一维数组,因为它几乎肯定会更快。
请注意,JIT 编译器完全有可能执行此优化(假设根据您的 OP 对乘法进行了硬编码),但值得明确地进行。
之所以说一维数组会更快是因为the latest compiler is lacking some of the optimisations for multi-dimensional array access, as discussed in this thread.
也就是说,您应该仔细计时,看看什么才是最快的。
正如 Eric Lippert 所说:"If you want to know which horse is faster, race your horses"。
C# 将多维数组存储为单个内存块,因此它们编译成几乎相同的东西。 (一个区别是要检查三组边界)。
即arr[x,y,z]
几乎等同于 arr[x + y*ny +z*nz*ny]
,通常具有相似的性能特征。
然而,确切的性能将取决于内存访问模式,以及这如何影响缓存一致性(至少对于大量数据而言)。您可能会发现 x
然后 y
然后 z
的嵌套循环可能比以不同顺序执行循环更快或更慢,如果一个人在保留当前使用的数据方面做得更好的话在处理器缓存中。
这在很大程度上取决于具体的算法,因此不可能给出对所有算法都正确的答案。
与 C 或 C++ 相比速度降低的另一个原因是边界检查,在一维数组的情况下仍然需要边界检查。然而,这些通常(但并非总是)会自动删除。
同样,确切的算法将影响优化器是否能够删除边界检查。
您的操作步骤如下:
- 使用
arr[x,y,z]
编写算法的简单版本。 - 如果足够快,您可以停下来。
- 否则分析算法以检查问题实际上是数组访问,分析内存访问模式等。