C# 在大列表中迭代并编辑所有列表项,而不会造成很多延迟?

C# 在大列表中迭代并编辑所有列表项,而不会造成很多延迟?,c#,C#,我正在遍历一个大列表,其中充满了矩形,每一帧它们应该下降1个像素,但由于矩形数量巨大,我得到了一个巨大的fps下降我的代码: for (var x = 0; x < Water3.Count(); x++ ) { bool intersect = false; Rectangle rect = Water3[x]; List<Rectangle> Water2 = new List<Rectangle>(Water3); Water2

我正在遍历一个大列表,其中充满了矩形,每一帧它们应该下降1个像素,但由于矩形数量巨大,我得到了一个巨大的fps下降我的代码:

for (var x = 0; x < Water3.Count(); x++ )
{
    bool intersect = false;
    Rectangle rect = Water3[x];
    List<Rectangle> Water2 = new List<Rectangle>(Water3);
    Water2.RemoveAt(x);
    rect.Y++;
    foreach (Rectangle check in Water2)
    {
        if (check.IntersectsWith(rect))
        {
            intersect = true;
            break;
        }
    }
    if (rect.Y >= 699 || intersect == true)
    {
        rect.Y--;
    }
    Water[x] = rect;
    frameGraphics.FillRectangle(new SolidBrush(Color.Red), Water3[x]);
}
for(var x=0;x=699 | | intersect==true)
{
右Y-;
}
水[x]=rect;
frameGraphics.FillRectangle(新的SolidBrush(颜色.红色),Water3[x]);
}
这是我目前的代码:

private void render()
{
    int framesRendered = 0;
    long startTime = Environment.TickCount;

    Bitmap frame = new Bitmap(Game.CANVAS_WIDTH, Game.CANVAS_HEIGHT);
    Graphics frameGraphics = Graphics.FromImage(frame);


    #region Brushes

    SolidBrush Black = new SolidBrush(Color.Black);
    SolidBrush Red = new SolidBrush(Color.Red);

    #endregion 

    while (true)
    {
        frameGraphics.FillRectangle(Black, 0, 0, Game.CANVAS_WIDTH, Game.CANVAS_HEIGHT);
        List<Rectangle> Water3 = new List<Rectangle>(Water);

        for (var x = 0; x < Water3.Count; x++)
        {
            Rectangle rect = Water3[x];
            rect.Y++;

            bool intersect = Water3.Where((t, i) => i != x).Any(check => check.IntersectsWith(rect));

            if (rect.Y >= 699 || intersect)
                rect.Y--;

            Water[x] = rect;
            frameGraphics.FillRectangle(Red, Water3[x]);
        }

        drawHandle.DrawImage(frame, 0, 0);

        //benchmarking
        framesRendered++;
        if (Environment.TickCount >= startTime + 1000)
        {
            Console.WriteLine("Engine: " + framesRendered + " fps");
            framesRendered = 0;
            startTime = Environment.TickCount;
private void render()
{
int framesRendered=0;
long startTime=Environment.TickCount;
位图帧=新位图(Game.CANVAS\u宽度,Game.CANVAS\u高度);
Graphics frameGraphics=Graphics.FromImage(frame);
#区域笔刷
SolidBrush黑色=新的SolidBrush(颜色为黑色);
SolidBrush红色=新的SolidBrush(颜色为红色);
#端区
while(true)
{
frameGraphics.FillRectangle(黑色,0,0,Game.CANVAS\u宽度,Game.CANVAS\u高度);
列表水3=新列表(水);
对于(var x=0;xi!=x).Any(check=>check.IntersectsWith(rect));
如果(矩形Y>=699 | |相交)
右Y-;
水[x]=rect;
frameGraphics.FillRectangle(红色,水3[x]);
}
drawHandle.DrawImage(框架,0,0);
//基准测试
框架描述++;
如果(Environment.TickCount>=startTime+1000)
{
控制台。写入线(“引擎:“+framesRendered+“fps”);
framesRendered=0;
startTime=Environment.TickCount;

您在循环中一次又一次地复制列表:

List<Rectangle> Water2 = new List<Rectangle>(Water3);
List Water2=新列表(Water3);

这将给您带来巨大的n^2性能影响。

正如Yishai已经说过的,您正在每个循环中创建一个巨大的列表Water3。这意味着在每个循环中分配和释放大量内存,这将对性能产生巨大影响。因此,更好地处理您已经拥有的列表

        for (var x = 0; x < Water3.Count; x++)
        {
            bool intersect = false;
            Rectangle rect = Water3[x];
            rect.Y++;

            for (var i = 0; i < Water3.Count; i++)
            {
                if (i == x)
                    continue;

                Rectangle check = Water3[i];
                if (check.IntersectsWith(rect))
                {
                    intersect = true;
                    break;
                }
            }

            if (rect.Y >= 699 || intersect)
                rect.Y--;

            Water[x] = rect;
            // painting 1000 rects like this takes about 12msec
            // frameGraphics.FillRectangle(Brushes.Red, rect);
        }

        // painting all 1000 rects at once will take only 3msec
        frameGraphics.FillRectangles(Brushes.Red, Water.ToArray());
for(var x=0;x=699 | |相交)
右Y-;
水[x]=rect;
//像这样绘制1000个矩形大约需要12秒
//frameGraphics.FillRectangle(画笔.Red,rect);
}
//一次绘制所有1000个矩形只需3秒
框架图形。填充矩形(画笔。红色,水。ToArray());
或者使用LINQ表达式:

        for (var x = 0; x < Water3.Count; x++)
        {
            Rectangle rect = Water3[x];
            rect.Y++;

            bool intersect = Water3.Where((t, i) => i != x).Any(check => check.IntersectsWith(rect));

            if (rect.Y >= 699 || intersect)
                rect.Y--;

            Water[x] = rect;

            // painting 1000 rects like this takes about 12msec
            // frameGraphics.FillRectangle(Brushes.Red, rect);
        }

        // painting all 1000 rects at once will take only 3msec
        frameGraphics.FillRectangles(Brushes.Red, Water.ToArray());
for(var x=0;xi!=x).Any(check=>check.IntersectsWith(rect));
如果(矩形Y>=699 | |相交)
右Y-;
水[x]=rect;
//像这样绘制1000个矩形大约需要12秒
//frameGraphics.FillRectangle(画笔.Red,rect);
}
//一次绘制所有1000个矩形只需3秒
框架图形。填充矩形(画笔。红色,水。ToArray());

关于内存泄漏的另一条评论。你不应该在循环中一次又一次地创建SolidBrush。而是在循环外创建笔刷,并将其放入using语句中,以便在之后处理。如果你需要一种典型的颜色,如:红色,则不要创建自己的笔刷,而是使用静态成员笔刷。红色in读取。

如果
Water3
是一个列表,则使用
.Count
属性而不是
.Count()
更改的.Count()to.count,但我仍然获得了巨大的fps下降tho。我该如何解决这个问题?因为我每次都需要重新创建这些列表。您不需要每次迭代都重新创建Water2。您在外部任何地方都不使用它。因此,要开始而不是复制列表,只需在Water3上迭代(使用for而不是foreach),如果索引匹配项不尝试比较。但该算法效率很低(n^2),您可以对Water3进行预排序,只在可能匹配的范围内搜索(例如rect.X到rect.X+宽度,然后停止)。这两种算法仍然会给我带来巨大的fps下降图像:()每个点代表我列表中的一个矩形。您是否尝试过在不修改它们的情况下绘制许多矩形?我猜是GDI+(…FillRectangle)对于这么多的对象来说太慢了。看起来你的画作还是相当昂贵的。你能把画作和计算画什么分开吗?你还需要在每一帧上填充矩形吗?如果大多数都没有改变,只画那些改变的。另一件小事,在循环之外创建solidbrush。更新了code,但仍然落后很多,我认为是这一行:frameGraphics.FillRectangle(黑色,0,0,Game.CANVAS\u宽度,Game.CANVAS\u高度);您不能只绘制已更改的矩形,因为整个画布将失效,因此您需要绘制所有内容。关键是一次发送所有矩形进行绘制。例如:如果单独绘制每个矩形(假设1000个矩形),则需要12秒。如果使用FillRectangles,则只需要3秒!