快速初始化大锯齿状阵列

时间:2013-07-23 03:25:20

标签: c# performance jagged-arrays

我有一个表示Grid的锯齿状数组,每个数组项都是CellGrid有2600行和2600列。我需要计算每个Cell的坐标,创建Cell对象的实例并将其添加到数组中。现在我正在使用的代码在我的计算机上占用3200-3800 ms。有没有办法让它更快?

public GridCell[][] Cells;
private void CreateCells(int cellWidth, int cellHeight, int startX, int startY)
    {          
        Cells = new GridCell[RowsCount][];
        for (int i = 0; i < RowsCount; i++)
        {
            Cells[i] = new GridCell[ColumnsCount];
            for (int j = 0; j < ColumnsCount; j++)
            {
                Point coordinate = new Point(startX + cellWidth * j, startY + cellHeight * i);
                Cells[i][j] = new GridCell(cellWidth, cellHeight, coordinate);
            }
        }
    }

3 个答案:

答案 0 :(得分:3)

考虑到您正在使用6760000个对象,您可以获得良好的性能。主要的时间可能是在堆上构建新对象。因此,正如您所观察到的那样,使用结构而不是类可以为您提供支持。

如果你有大的CPU缓存,你也可以尝试使用单个数组,如:

public GridCell[] Cells = new GridCell[RowsCount * ColumnsCount];

使用寻址,例如:

Cells[i * ColumnsCount + j] = x;

答案 1 :(得分:2)

考虑使用Parallel.For - 这样的事情对多线程来说是微不足道的。

如图所示,如果您愿意更改功能(在这种情况下使用结构,但分配单个数组也可能有一些好处),可以在其他地方找到更大的初始增益。仍然可以使用线程来提高性能。 / p>

一些简单的测试:

//Single Threaded          : 1701, 1825, 1495, 1606
//Multi Threaded           : 1516, 1446, 1581, 1401
//Struct Single Threaded   :  154,  157,  153,  151
//Struct MultiThreaded     :  104,  107,  106,  103

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            while (true)
            {
                Benchmark("Single Threaded", () => CreateCells(1, 1, 0, 0));
                Benchmark("Multi Threaded", () => CreateCellsThreaded(1, 1, 0, 0));
                Benchmark("Struct Single Threaded", () => CreateStructCells(1, 1, 0, 0));
                Benchmark("Struct MultiThreaded", () => CreateStructCellsThreaded(1, 1, 0, 0));
            }
        }

        static void Benchmark(string Name, Action test)
        {
            var sw = Stopwatch.StartNew();
            test();
            UpdateResults(Name, sw.ElapsedMilliseconds.ToString());
            GC.Collect();
        }

        static Dictionary<string, string> results = new Dictionary<string, string>();
        static void UpdateResults(string key, string value)
        {
            value = value.PadLeft(4);
            if (results.ContainsKey(key))
                results[key] += ", " + value;
            else
                results[key] = value;

            Console.Clear();
            foreach (var kvp in results) Console.WriteLine(kvp.Key.PadRight(25) + ": " + kvp.Value);
        }

        const int RowsCount = 2600;
        const int ColumnsCount = 2600;

        public class Point
        {
            public int x;
            public int y;
            public Point(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        }

        public class GridCell
        {
            public int width;
            public int height;
            public Point point;
            public GridCell(int width, int height, Point point)
            {
                this.width = width;
                this.height = height;
                this.point = point;
            }
        }

        public struct StructPoint
        {
            public int x;
            public int y;
            public StructPoint(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        }


        public struct StructGridCell
        {
            public int width;
            public int height;
            public StructPoint point;
            public StructGridCell(int width, int height, StructPoint point)
            {
                this.width = width;
                this.height = height;
                this.point = point;
            }
        }

        private static void CreateCells(int cellWidth, int cellHeight, int startX, int startY)
        {
            var Cells = new GridCell[RowsCount][];
            for (int i = 0; i < RowsCount; i++)
            {
                Cells[i] = new GridCell[ColumnsCount];
                for (int j = 0; j < ColumnsCount; j++)
                {
                    Point coordinate = new Point(startX + cellWidth * j, startY + cellHeight * i);
                    Cells[i][j] = new GridCell(cellWidth, cellHeight, coordinate);
                }
            }
        }
        private static void CreateCellsThreaded(int cellWidth, int cellHeight, int startX, int startY)
        {
            var Cells = new GridCell[RowsCount][];
            Parallel.For(0, RowsCount, new ParallelOptions { MaxDegreeOfParallelism = 4 }, i =>
            {
                Cells[i] = new GridCell[ColumnsCount];
                for (int j = 0; j < ColumnsCount; j++)
                {
                    Point coordinate = new Point(startX + cellWidth * j, startY + cellHeight * i);
                    Cells[i][j] = new GridCell(cellWidth, cellHeight, coordinate);
                }
            });
        }

        private static void CreateStructCells(int cellWidth, int cellHeight, int startX, int startY)
        {
            var Cells = new StructGridCell[RowsCount][];
            for (int i = 0; i < RowsCount; i++)
            {
                Cells[i] = new StructGridCell[ColumnsCount];
                for (int j = 0; j < ColumnsCount; j++)
                {
                    var coordinate = new StructPoint(startX + cellWidth * j, startY + cellHeight * i);
                    Cells[i][j] = new StructGridCell(cellWidth, cellHeight, coordinate);
                }
            }
        }
        private static void CreateStructCellsThreaded(int cellWidth, int cellHeight, int startX, int startY)
        {
            var Cells = new StructGridCell[RowsCount][];
            Parallel.For(0, RowsCount, i =>
            {
                Cells[i] = new StructGridCell[ColumnsCount];
                for (int j = 0; j < ColumnsCount; j++)
                {
                    var coordinate = new StructPoint(startX + cellWidth * j, startY + cellHeight * i);
                    Cells[i][j] = new StructGridCell(cellWidth, cellHeight, coordinate);
                }
            });
        }
    }
}

答案 2 :(得分:1)

您在评论中提到GridCellPoint都是类。类是迄今为止最常见的创建方法,但是如果您对不同的语义很好并且它们主要是保存数据而不是功能,那么您可以将它们转换为结构。

结构几乎就像一个类,但它是一个值类型而不是引用类型。这意味着代码如下:

Point a = new Point(0, 0);
Point b = a;
b.X = 5;
Console.WriteLine(a);

...如果它是一个结构,则会打印0,如果它是一个类,则会打印5

这些语义允许将结构嵌入到其他内容中,而不必在堆上拥有自己的空间。从堆中分配可能很昂贵,因此如果您可以分配一个结构数组,则只需要进行一次分配而不是多次分配。