二维数组 vs 一维数组

6
我已经阅读了关于二维数组与一维数组性能比较的问题 (Performance of 2-dimensional array vs 1-dimensional array)。但是结论中说,二者可能相同(取决于地图自身的映射函数,C语言会自动处理)。...
我有一个矩阵,其中有1,000列和440,000,000行,每个元素都是C#中的双精度浮点数。
如果我在内存中进行一些计算,从性能角度考虑,哪种方法更好?(请注意,我有足够的内存来容纳这么多信息)...

3
“Monstrous” quantity of information?大约是330MB,这就是浏览器仅打开几个选项卡时所使用的数据量。 - Konrad Morawski
当然,访问一维数组比访问二维数组更快,但如果您需要一个二维数组,则使用一维数组模拟它需要手动进行计算,否则这些计算将自动完成,并且这些计算可能会有相同的时间惩罚。 - Olivier Jacot-Descombes
那么访问一维数组会更快,我只需要执行 *width 操作对吗? - edgarmtze
1
作为一般的编程规则,总是更好地追求简单、易懂和逻辑清晰的解决方案。优化往往会导致糟糕和复杂的解决方案。这并不意味着你不能进行优化,但你不应该从一开始就这样做。如果你发现你的代码太慢或者太耗内存,那么稍后再进行优化。如果你的解决方案结构良好,那么以后实施变更应该很容易。 - Olivier Jacot-Descombes
如果您真正将1D数组用作1D数组,并且不必进行索引计算(宽度计算)以便像2D数组一样使用它,则1D数组只会更快。这些计算正是使其变慢的原因。 - Olivier Jacot-Descombes
我很惊讶现在还没有人提到您应该进行性能分析。尝试两种方法,对您的代码进行性能分析并看看哪个更好。唯一真正能回答这个问题的是 。我们可以整天谈论理论(并且有一些好观点),但最终唯一重要的是,在您实施它时是否会产生实际差异。 - Mike Bailey
3个回答

7
如果你问的是哪个更好,一个大小为1000x44000的二维数组还是一个大小为44000000的一维数组,那么在内存方面有什么不同呢?你仍然拥有相同数量的元素!在性能和可读性方面,二维数组可能更好。想象一下,在一维数组中手动查找每个列或行时,而你在二维数组中确切地知道它们在哪里。

6

这取决于您执行的操作数量。在下面的示例中,我设置了数组的值2500次。数组的大小为(1000 * 1000 * 3)。1D数组花费了40秒,而3D数组花费了1:39分钟。

var startTime = DateTime.Now;
Test1D(new byte[1000 * 1000 * 3]);
Console.WriteLine("Total Time taken 1d = " + (DateTime.Now - startTime));

startTime = DateTime.Now;
Test3D(new byte[1000,1000,3], 1000, 1000);
Console.WriteLine("Total Time taken 3D = " + (DateTime.Now - startTime));

public static void Test1D(byte[] array)
{
    for (int c = 0; c < 2500; c++)
    {
        for (int i = 0; i < array.Length; i++)
        {
            array[i] = 10;
        }
    }
}

public static void Test3D(byte[,,] array, int w, int h)
{
    for (int c = 0; c < 2500; c++)
    {
        for (int i = 0; i < h; i++)
        {
            for (int j = 0; j < w; j++)
            {
                array[i, j, 0] = 10;
                array[i, j, 1] = 10;
                array[i, j, 2] = 10;
            }
         }
     }
}

1
这是唯一一个提供证据而非意见的答案!我在以下博客中找到了关于为什么2D数组需要更长时间的解释:https://medium.com/csharp-architects/high-performance-arrays-in-c-2d55c04d37b5 简而言之,当运行时使用特殊的IL指令访问1D数组时,对于nD数组,它需要调用方法。 - Isolin
这确实很有帮助,因为有经验的证据支持。但是当您想要对数组进行更多操作而不仅仅是分配值时,而是想要操作某些值时,您必须执行索引计算。因此,为了进行“公正”的比较测试,您不应该仅在循环中使用i,而应该使用两个循环和位置计算,就像在设置特定值的X、Y、Z点时所做的那样。 我已经这样做了,手动计算索引花费了14.3秒,而使用2D数组只花费了11.8秒。 - OneTrickDragon

1

double[1000,44000]double[44000000]之间的差异不会很大。

你可能更适合使用[,]版本(让编译器自行处理寻址)。但是你的计算模式很可能会产生更大的影响(局部性和缓存使用)。

还要考虑数组的数组变体double[1000][]。这是Jitter的已知“特性”,它无法消除[,]数组中的范围检查。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接