在性能方面有啥更好的?类型[,] 还是类型[][]?

Posted

技术标签:

【中文标题】在性能方面有啥更好的?类型[,] 还是类型[][]?【英文标题】:What's better in regards to performance? type[,] or type[][]?在性能方面有什么更好的?类型[,] 还是类型[][]? 【发布时间】:2010-09-15 04:43:03 【问题描述】:

在 C# 中使用二维数组 (type[,]) 还是数组数组 (type[][]) 性能更高?

特别是对于初始分配和项目访问

【问题讨论】:

另见why-are-multi-dimensional-arrays-in-net-slower-than-normal-arrays? 【参考方案1】:

当然,如果一切都失败了……测试一下!以下给出(在控制台的“发布”中):

Size 1000, Repeat 1000
    int[,] set: 3460
    int[,] get: 4036 (chk=1304808064)
    int[][] set: 2441
    int[][] get: 1283 (chk=1304808064)

所以锯齿状数组更快,至少在这个测试中是这样。有趣的!然而,这是一个相对很小的因素,所以我仍然会坚持更好地描述我的要求。除了一些特定的(高 CPU/处理)场景外,可读性/可维护性应该胜过小的性能提升。不过,这取决于你。

请注意,此测试假定您访问数组的次数比创建数组的次数要多,因此我没有包括创建时间,我会预计矩形会稍微快一些,除非内存高度碎片化.

using System;
using System.Diagnostics;
static class Program

    static void Main()
    
        Console.WriteLine("First is just for JIT...");
        Test(10,10);
        Console.WriteLine("Real numbers...");
        Test(1000,1000);

        Console.ReadLine();
    

    static void Test(int size, int repeat)
    
        Console.WriteLine("Size 0, Repeat 1", size, repeat);
        int[,] rect = new int[size, size];
        int[][] jagged = new int[size][];
        for (int i = 0; i < size; i++)
         // don't count this in the metrics...
            jagged[i] = new int[size];
        
        Stopwatch watch = Stopwatch.StartNew();
        for (int cycle = 0; cycle < repeat; cycle++)
        
            for (int i = 0; i < size; i++)
            
                for (int j = 0; j < size; j++)
                
                    rect[i, j] = i * j;
                
            
        
        watch.Stop();
        Console.WriteLine("\tint[,] set: " + watch.ElapsedMilliseconds);

        int sum = 0;
        watch = Stopwatch.StartNew();
        for (int cycle = 0; cycle < repeat; cycle++)
        
            for (int i = 0; i < size; i++)
            
                for (int j = 0; j < size; j++)
                
                    sum += rect[i, j];
                
            
        
        watch.Stop();
        Console.WriteLine("\tint[,] get: 0 (chk=1)", watch.ElapsedMilliseconds, sum);

        watch = Stopwatch.StartNew();
        for (int cycle = 0; cycle < repeat; cycle++)
        
            for (int i = 0; i < size; i++)
            
                for (int j = 0; j < size; j++)
                
                    jagged[i][j] = i * j;
                
            
        
        watch.Stop();
        Console.WriteLine("\tint[][] set: " + watch.ElapsedMilliseconds);

        sum = 0;
        watch = Stopwatch.StartNew();
        for (int cycle = 0; cycle < repeat; cycle++)
        
            for (int i = 0; i < size; i++)
            
                for (int j = 0; j < size; j++)
                
                    sum += jagged[i][j];
                
            
        
        watch.Stop();
        Console.WriteLine("\tint[][] get: 0 (chk=1)", watch.ElapsedMilliseconds, sum);
    

【讨论】:

我在 msdn 的 .NET 优化博客中看到了相同的结果。【参考方案2】:

我相信 [,] 可以分配一个连续的内存块,而 [][] 是 N+1 个块分配,其中 N 是第一个维度的大小。所以我猜想 [,] 在初始分配时更快。

Access 可能大致相同,只是 [][] 会涉及一个额外的取消引用。除非你处于一个非常紧的循环中,否则它可能是一个洗涤。现在,如果您正在执行诸如图像处理之类的事情,您在 之间 行而不是逐行遍历,则引用的局部性将发挥重要作用,并且 [,] 可能会超出 [][ ] 取决于您的缓存大小。

正如 Marc Gravell 所说,使用情况是评估性能的关键......

【讨论】:

【参考方案3】:

这真的取决于。 MSDN 杂志文章 Harness the Features of C# to Power Your Scientific Computing Projects 是这样说的:

虽然矩形阵列在结构和性能方面通常优于锯齿阵列,但在某些情况下,锯齿阵列可能会提供最佳解决方案。如果您的应用程序不需要对数组进行排序、重新排列、分区、稀疏或较大,那么您可能会发现锯齿状数组的性能非常好。

【讨论】:

【参考方案4】:

type[,] 会更快。不仅因为偏移量计算更少。主要是因为更少的约束检查,更少的内存分配和更大的内存本地化。 type[][] 不是单个对象——它是 1 + N 个必须分配的对象,并且可以彼此远离。

【讨论】:

该答案以绝对声明开头,这(以我的卑微经验)不正确...据我所知(我不知道一切),多下标数组实际上在每次访问时都会进行更多计算因为我们必须将下标“展平”为实际的单整数索引...例如,给定 var a=int[16,16] 那么 a[1,1] 实际上是 a[16*1+1] -> a [17] ...并且该 row*ROWS+col 计算花费的时间(平均而言)比返回等效锯齿状数组中 a[1][1] 的值所需的两个取消引用时间长...这就是为什么我不赞成这个回答。抱歉,恕我直言,这是误导。

以上是关于在性能方面有啥更好的?类型[,] 还是类型[][]?的主要内容,如果未能解决你的问题,请参考以下文章

性能方面哪个更好:对象原型还是构造函数本机函数? [复制]

在功能方面,此代码的分配有啥不同吗?

MYSQL性能调优07_MySQL数据类型选择数值类型日期和时间字符串

请问函数的返回值类型那里,写“类名”和“类名&”有啥区别?

请问函数的返回值类型那里,写“类名”和“类名&”有啥区别?

String为值类型还是引用类型