c#资源争用

本文关键字:争用 资源 | 更新日期: 2023-09-27 18:07:54

我正在为AI单位创建一个流场,并试图加快一些线程代码。我的测试网格大小是2000 x 2000,目前生成时间降到了5.5秒。对代码的分析指出了一些看起来很奇怪的东西。我对线程使用的方法平均报告140个包容性争用,其中65个用于这一行。

var neighbours = GetNeighbors4(cell.Point);

及以下是被调用的方法。

private IEnumerable<IntegrationCell> GetNeighbors4(Point point)
        {
            var sizeX = _size.X - 1;
            var sizeY = _size.Y - 1;
            var x = point.X;
            var y = point.Y;
            //corners
            if (x == 0 && y == 0)
            {
                return new[]
                {
                    Cells[1, 0],
                    Cells[0, 1]
                };
            }
            if (x == sizeX && y == 0)
            {
                return new[]
                {
                    Cells[sizeX - 1, 0],
                    Cells[sizeX, 1]
                };
            }
            if (x == 0 && y == sizeY)
            {
                return new[]
                {
                    Cells[0, sizeY - 1],
                    Cells[1, sizeY]
                };
            }
            if (x == sizeX && y == sizeY)
            {
                return new[]
                {
                    Cells[sizeX - 1, sizeY],
                    Cells[sizeX, sizeY - 1]
                };
            }
            //top row
            if (y == 0)
            {
                return new[]
                {
                    Cells[x - 1, 0],
                    Cells[x + 1, 0],
                    Cells[x, 1]
                };
            }
            //bottom row
            if (y == sizeY)
            {
                return new[]
                {
                    Cells[x - 1, y],
                    Cells[x + 1, y],
                    Cells[x, y - 1]
                };
            }
            //left column
            if (x == 0)
            {
                return new[]
                {
                    Cells[0, y - 1],
                    Cells[0, y + 1],
                    Cells[1, y]
                };
            }
            //right column
            if (x == sizeX)
            {
                return new[]
                {
                    Cells[x, y - 1],
                    Cells[x, y + 1],
                    Cells[x - 1, y]
                };
            }
            //everything else
            return new[]
            {
                Cells[x, y - 1],
                Cells[x, y + 1],
                Cells[x - 1, y],
                Cells[x + 1, y]
            };
        }

Cells是一个简单的二维数组,用来表示网格

IntegrationCell[,] Cells; 

现在它的工作方式是在网格中给定一个目标细胞,我从目标中像"波"或"涟漪"一样走出来。波的每一次迭代都离目标更远。当我这样做的时候,随着与目标距离的增加,每次迭代都有更多的单元格。对于每次迭代中的每个单元格,我生成一个新的线程来计算单元格的成本,并返回需要计算/重新计算的新单元格列表。还有很多事情发生,但基本上就这些了。在到达地图边缘之前,我的峰值大约是120个线程,每次迭代的单元格开始减少,直到一个都没有剩下。

这是为每个单元运行的线程的完整方法。(我可以同时运行100多个)

private IEnumerable<IntegrationCell> CostStep(IntegrationCell cell)
        {
            var result = new List<IntegrationCell>();  ''14 contentions
            var costBlock = _costfield.Cells[cell.Point.X, cell.Point.Y];
            if (costBlock.Cost == 255)
                return result;
            var neighbours = GetNeighbors4(cell.Point); ''65 contentions
            foreach (var neighbour in neighbours)  ''18 contentions
            {
                var newCost = costBlock.Cost + neighbour.Cost;
                if (cell.Cost > newCost)
                    cell.Cost = newCost;
                var childCostBlock = _costfield.Cells[neighbour.Point.X, neighbour.Point.Y];
                var newChildCost = cell.Cost + childCostBlock.Cost;
                if (childCostBlock.Cost == 255)
                    neighbour.Cost = 255;
                else if (neighbour.Cost > newChildCost)
                {
                    neighbour.Cost = newChildCost;
                    result.Add(neighbour);  ''39 contentions
                }
            }
            return result;
        }

我对每一行报告的争议都做了注释。每次运行的争用都不同,但我不能理解的是为什么我要从数组中读取争用?是的,如果需要,我正在更新数组/单元格及其邻居,每个单元格可以计算不止一次。

c#资源争用

对于每次迭代中的每个cell,我生成一个新线程…

可能这就是问题所在。由于您正在进行CPU限制计算,因此仅使用CPU拥有的计算机的线程数,由静态属性

指示:
System.Environment.ProcessorCount

否则,您将尝试调度太多,导致大量争用和上下文切换。

我的意思是,更多的线程并不意味着更快,实际上,它可能使应用程序变慢,因为线程管理开销。当你有I/O绑定操作时,你使用更多的线程,因此许多线程空闲等待其他地方发生的事情(例如:web服务调用,数据库操作,传入请求....)

看一下这个答案:https://stackoverflow.com/a/12021285/307976,以及如何限制PLINQ的并行性