无法优化简单的方法

时间:2019-04-25 22:21:52

标签: c# performance

我成功实现了这篇论文(仅用于我自己的研究)http://eprints.uwe.ac.uk/15260/,但是当遵循作者的特定实现时,我遇到了性能问题。使故事简单明了。我有一个Cell类,每个Cell存储在多维数组中,代表一个标量字段。 Cell类具有一种确定是否包含点的方法,这种遏制测试是导致我的代码出现严重性能问题的原因。

为澄清起见,在Cell类中,我有一个名为BoundingBox的方法(此处未显示),该方法计算一个正方形的4个顶点以确定容纳区域。这就是每个单元知道它是否包含粒子/代理的方式。在Contains方法中,m_domainX.Min…等用于保存包含区域的最小和最大坐标。我也只打电话给BoundingBox一次;我只是在类的构造函数中调用它。但是,Containment方法是在每个更新帧中计算的。

我通常使用150X150的阵列,大约4,000个粒子/试剂。基本上,数组越大,性能越低

我试图并行化该方法,但没有得到任何性能提升。

为说明起见,下面是一些模拟图像

enter image description here

   // This method belons to the Cell<T> class, and will be used every update frame
    public void Contains(List<PhysarumAgent> particles)
    {
        int ptsCount = 0;

        foreach (var particle in particles)
        {
            if (particle.ForewordSensorB.X >= m_domainX.Min &&
                particle.ForewordSensorB.X <= m_domainX.Max &&
                particle.ForewordSensorB.Y >= m_domainY.Min &&
                particle.ForewordSensorB.Y <= m_domainY.Max)
            {
                ptsCount++;
            }
        }


 m_numAgentsInCell = ptsCount;
            if (ptsCount > 1) m_occupied = true;
            else m_occupied = false;
    }

    // This method belongs to another class. It iterates over the scalar field and calls 
    // the Contains() method for every cell in the field. Computed every update frame.
    private static void ComputeField(SharpField2D<double> scalarField,
        List<PhysarumAgent> PhysarumAgentPopulation)
    {
        ParallelOptions paraOpts = new ParallelOptions();
        paraOpts.MaxDegreeOfParallelism = System.Environment.ProcessorCount;

        Parallel.For(0, scalarField.Columns, paraOpts, i =>
        {
            Parallel.For(0, scalarField.Rows, paraOpts, j =>
            {
                scalarField.Field[i, j].Contains(PhysarumAgentPopulation);
            });
        });
    }

有任何指针将是很棒的,因为我不确定为什么这个简单的方法会引起很多问题。

1 个答案:

答案 0 :(得分:0)

  1. 您的比较太多了。对于150x150的单元和4000个粒子,您必须测试90M次单元与粒子的比较。

如果您的单元格形成规则的网格,则根本不需要运行任何测试。取而代之的是对粒子进行迭代,为每个粒子计算单元格索引,即将坐标除以单元格大小,然后调用Math.Floor,强制转换为int。如果您需要计算每个单元的点数计数器,或者以其他方式对每个单元聚集粒子,则以允许在每个单元中存储正在聚集的状态并逐步更新状态的方式编写该聚集代码。您可能需要遍历所有初始化的单元格,然后在处理所有粒子之后进行迭代,但这只需要按每个单元格而不是像当前比较那样按每个(单元格,粒子)对完成。

  1. 此外,您可能有太多随机RAM访问。如果单元格和粒子都是类而不是结构,则在对它们的数组进行迭代时,您将在每次迭代中进行随机指针追逐,如果您的数据集足够大,则每次缓存都会丢失。因此,有时从类切换到结构是有意义的。与引用类型不同,数组或结构列表保存在连续的RAM地址中,即,迭代速度更快。