【问题标题】:Why is my C# nested for loop slow?为什么我的 C# 嵌套 for 循环很慢?
【发布时间】:2017-08-19 12:39:21
【问题描述】:

我正在创建一个作为学校项目的游戏,并认为使用颜色映射来创建关卡是个好​​主意,但是由于某种原因,我使用的方法非常很慢。

        public List<Entity> LoadLevel(Level level)
    {
        List<Entity> ents = new List<Entity>();
        Color[] clrs = new Color[level.getColorMap.Height*level.getColorMap.Width];
        level.getColorMap.GetData(clrs);
        for (int x = 0; x < level.getColorMap.Width; x++)
        {
            for (int y = 0; y < level.getColorMap.Height; y++)
            {
                if (clrs[x + y * level.getColorMap.Width] == new Color(0, 0, 0))
                {
                    ents.Add(new Terrain(new Vector2(x, y)));
                    ents.Last().Animation.setImageIndex(0);
                    ents.Last().Animation.Play();
                }
                if (clrs[x + y * level.getColorMap.Width] == new Color(6, 6, 6))
                {
                    ents.Add(new Terrain(new Vector2(x, y)));
                    ents.Last().Animation.setImageIndex(6);
                    ents.Last().Animation.setSpeed(69);
                    ents.Last().Animation.Play();
                }
                if (clrs[x + y * level.getColorMap.Width] == new Color(9, 9, 9))
                {
                    ents.Add(new Terrain(new Vector2(x, y)));
                    ents.Last().Animation.setImageIndex(9);
                    ents.Last().Animation.setSpeed(69);
                    ents.Last().Animation.Play();
                }
            }
        }
        return ents;


    }

我在LoadContent()中调用了这个函数,执行大约需要半分钟,为什么这么慢?

【问题讨论】:

  • 这个更适合code review
  • level.getColorMap.Heightlevel.getColorMap.Width 有多大?
  • 它们都是 2048 大。
  • 我们不知道所有这些动画方法的作用。注释所有以“ents.”开头的行。它有帮助,问题不在此代码中。
  • @AntonínLejsek 它可能在这段代码中。例如,getColorMap 可能正在从磁盘加载颜色图。你是对的,“成本”在这段代码之外,但它仍然可以在这里改进。在任何情况下,不断访问level.getColorMaplevel.getColorMap.Width 而不是将其存储在局部变量中,这有点异味。还有就是缺少else if而不是多余的计算。

标签: c# performance xna nested-loops monogame


【解决方案1】:

我对编码风格有一些注释。很可能这不是您的问题的原因,但最好早点知道。一般来说,您应该避免做重复和不必要的工作。我什至不会称之为优化,我会称之为规则。这应该是你一直编码的方式。

  • 如果level.getColorMap 需要一段时间怎么办?即使您不需要这样做,您也会一遍又一遍地调用它。你通常不应该依赖这样一个事实,即房产很便宜。调用一次并记住它的结果。

  • ents.Last() 相当快,但不是免费的。如果您不需要它,请不要调用它。构建新地形并记住指向它的指针。

  • 每个循环中的新Color(0, 0, 0) 都不好。不要将循环提升视为理所当然。即使您实际上需要三个颜色对象,您也很可能会构造 12000000 个颜色对象。

  • 您的代码也有很多重复性。通常,在复制和粘贴代码之前要三思。干燥

  • 循环顺序错误。您从一行跳到另一行破坏了缓存位置。您应该处理整行,然后转到下一个。

  • 只需要加法时避免乘法。

改进示例:

public void AddTerrain(List<Entity> ents, int selector, int x, int y)
{
    Terrain newT = new Terrain(new Vector2(x, y));
    ents.Add(newT);
    var animation = newT.Animation;
    animation.setImageIndex(selector);
    if (selector > 0)
    {
        animation.setSpeed(69);
    }
    animation.Play();
}



public List<Entity> LoadLevel(Level level)
{
    List<Entity> ents = new List<Entity>();
    var colorMap = level.getColorMap;
    int colorMapWidth = colorMap.Width;
    int colorMapHeight = colorMap.Height;
    Color[] clrs = new Color[colorMapWidth * colorMapHeight];
    Color[] colors = new Color[] { new Color(0, 0, 0), new Color(6, 6, 6), new Color(9, 9, 9) };
    colorMap.GetData(clrs);

    int ci = 0;
    for (int y = 0; y < colorMapHeight; y++)
    {
        for (int x = 0; x < colorMapWidth; x++)
        {
            Color c = clrs[ci++];
            for (int i = 0; i < colors.Length; ++i)
            {
                if (c == colors[i])
                {
                    AddTerrain(ents, c.R, x, y);
                    break;
                }
            }
        }
    }

    return ents;
}

【讨论】:

  • 非常好的建议。反转 x 和 y 循环可能是最大的变化。缓存是很重要的东西。
【解决方案2】:

(代表 OP 发布).

问题其实出在terrainobject的构造函数中,创建collider的函数貌似优化得很差,感谢帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-17
    相关资源
    最近更新 更多