C# 什么';就性能而言,它更好吗?类型[,]还是类型[]?

C# 什么';就性能而言,它更好吗?类型[,]还是类型[]?,c#,performance,arrays,C#,Performance,Arrays,在C#中使用二维数组(type[,])或数组数组(type[][])更有效吗 特别是对于初始分配和项目访问我认为[,]可以分配一个连续的内存块,而[]是N+1块分配,其中N是第一维度的大小。所以我猜,[,]在初始分配上更快 访问可能大致相同,只是[][]将涉及一个额外的解引用。除非你处于一个异常紧张的循环中,否则这可能是一次清洗。现在,如果您正在执行图像处理之类的操作,即在行之间引用,而不是逐行遍历,那么引用的位置将起到很大的作用,[,]可能会超出[],这取决于您的缓存大小 正如Marc Gra

在C#中使用二维数组(
type[,]
)或数组数组(
type[][]
)更有效吗


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

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

访问可能大致相同,只是[][]将涉及一个额外的解引用。除非你处于一个异常紧张的循环中,否则这可能是一次清洗。现在,如果您正在执行图像处理之类的操作,即在行之间引用,而不是逐行遍历,那么引用的位置将起到很大的作用,[,]可能会超出[],这取决于您的缓存大小


正如Marc Gravell所提到的,使用是评估性能的关键…

类型[,]将工作得更快。不仅因为偏移量计算较少。主要是因为更少的约束检查、更少的内存分配和更大的内存本地化。类型[][]不是一个单独的对象——它是必须分配的1+N个对象,并且可以彼此分开。

当然,如果其他所有操作都失败了。。。试试看!以下给出(在控制台的“释放”中):

所以锯齿阵列更快,至少在本测试中是这样。有趣!然而,这是一个相对较小的因素,所以我仍然会坚持使用更好地描述我的需求的方法。除了一些特定的(高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);
    }
}
使用系统;
使用系统诊断;
静态类程序
{
静态void Main()
{
WriteLine(“第一个只是用于JIT…”);
试验(10,10);
控制台。WriteLine(“实数…”);
测试(10001000);
Console.ReadLine();
}
静态空隙试验(整数大小,整数重复)
{
WriteLine(“大小{0},重复{1}”,大小,重复);
int[,]rect=新的int[大小,大小];
int[][]锯齿状=新int[size][];
对于(int i=0;i
这要看情况而定。MSDN杂志的文章说:

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


我在msdn的一个.NET优化博客上看到了同样的结果。这个答案是从绝对陈述开始的,这(以我微薄的经验)是不正确的。。。据我所知(我不知道一切),多下标数组实际上会在每次访问时进行更多的计算,因为我们必须将下标“展平”为实际的单整数索引。。。例如给定var a=int[16,16],那么a[1,1]实际上是a[16*1+1]>a[17]。。。而row*ROWS+col计算所需的时间(平均)比返回等价交错数组中a[1][1]的值所需的两次解引用所需的时间更长。。。这就是为什么我否决了这个答案。很抱歉,但我认为这是误导。另请参见
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);
    }
}