1

我有一个代表 a 的锯齿状数组,数组的Grid每个项目都是 a Cell。有Grid2600 行和 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);
            }
        }
    }
4

3 回答 3

3

考虑到您正在处理 6760000 个对象,您的性能很好。主要时间可能花在在堆上构建新对象上。因此,正如您所观察到的,使用结构而不是类会给您带来提升。

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

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

与寻址,如:

Cells[i * ColumnsCount + j] = x;
于 2013-07-23T03:58:56.173 回答
2

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

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

一些简单的测试:

//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);
                }
            });
        }
    }
}
于 2013-07-23T03:58:23.563 回答
1

您在评论中提到两者GridCell都是Point类。到目前为止,类是最常见的创建对象,但如果您对不同的语义感到满意,并且它们主要保存数据而不是功能,您可以将它们转换为结构。

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

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

0…如果它是一个结构,5如果它是一个类,将打印出来。

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

于 2013-07-23T03:54:14.763 回答