【问题标题】:Optimizing a high-traffic function in XNA优化 XNA 中的高流量功能
【发布时间】:2010-12-11 20:40:17
【问题描述】:

我有一个每次更新调用数十万次的函数,我需要对其进行优化。现在,我通常遵循“不要过早优化”的规则,但这是一个关键功能,几乎我所有的代码时间都花在了上面,所以你可以提出的任何建议都会有所帮助。我也不熟悉任何可用于优化 XNA 或 c# 代码的技巧和窍门。你能帮帮我吗?

if (linearPosition.Y < _min.Y || linearPosition.Y > _max.Y)// the nonlinear space commisioned doesn't cover it so that's the behavior i want, same case with next line
{
    return linearPosition;
}
if (linearPosition.X < _min.X || linearPosition.X > _max.X)
{
    return linearPosition;
}
PositionData[] fourNearestPoints = new PositionData[4] 
{
    new PositionData {distance = float.MaxValue},
    new PositionData {distance = float.MaxValue},
    new PositionData {distance = float.MaxValue},
    new PositionData {distance = float.MaxValue}
};

for (int x = 0; x < _restPositions.GetLength(0); x++)
{
    for (int y = 0; y < _restPositions.GetLength(1); y++)
    {
        PositionData temp = new PositionData
        {
            indexX = x,
            indexY = y,
            value = _restPositions[x,y],
            distance = (linearPosition - _restPositions[x,y]).Length()
        };
        if (temp.distance < fourNearestPoints[0].distance)
        {
            fourNearestPoints[3] = fourNearestPoints[2];
            fourNearestPoints[2] = fourNearestPoints[1];
            fourNearestPoints[1] = fourNearestPoints[0];
            fourNearestPoints[0] = temp;
        }
    }
}
Vector2 averageRestVector = new Vector2((fourNearestPoints[0].value.X +
    fourNearestPoints[1].value.X +
    fourNearestPoints[2].value.X +
    fourNearestPoints[3].value.X) / 4,
    (fourNearestPoints[0].value.Y +
    fourNearestPoints[1].value.Y +
    fourNearestPoints[2].value.Y +
    fourNearestPoints[3].value.Y) / 4);
Vector2 averageDeformedVector = new Vector2((_deformedPositions[fourNearestPoints[0].indexX, fourNearestPoints[0].indexY].X +
    _deformedPositions[fourNearestPoints[1].indexX, fourNearestPoints[1].indexY].X +
    _deformedPositions[fourNearestPoints[2].indexX, fourNearestPoints[2].indexY].X +
    _deformedPositions[fourNearestPoints[3].indexX, fourNearestPoints[3].indexY].X) / 4,
    (_deformedPositions[fourNearestPoints[0].indexX, fourNearestPoints[0].indexY].Y +
    _deformedPositions[fourNearestPoints[1].indexX, fourNearestPoints[1].indexY].Y +
    _deformedPositions[fourNearestPoints[2].indexX, fourNearestPoints[2].indexY].Y +
    _deformedPositions[fourNearestPoints[3].indexX, fourNearestPoints[3].indexY].Y) / 4);

Vector2 displacement = averageDeformedVector - averageRestVector;
return linearPosition + displacement;

【问题讨论】:

  • 查看更新的答案不是每次都创建temp
  • 添加了关于 LengthSquared 的注释
  • 另外 - 我认为你的代码有问题......如果我们测试的点不是 最接近的,但比第二个更接近,会发生什么-最近的?您可能还需要 3 次针对 _1、_2、_3 的距离测试
  • 我将变量距离初始化为 float.MaxValue,然后仅在距离低于我假设的列表中的第一项时对变量进行洗牌(丢弃最后一项并将每个项向上移动一项)是最接近的。因此,在任何给定时间,列表中的第 3 项只有在比列表中的第 4 项更近但比第 2 项更远的情况下才能到达那里。
  • 这里有一个额外的想法;我想知道您是否可以在您考虑的最大距离周围构建一个框(即,一个正方形,其“半径”为最近点_3 的距离(inc. sqrt))。然后,您可以仅通过 x/y 排除候选点。每当您找到一个新的最近点_3 时,您都需要维护该框(使其更小)。

标签: c# .net optimization xna


【解决方案1】:

我要尝试的第一件事是丢失fourNearestPoints 数组...也许只对最近的4 个位置使用4 个变量。你总是用常量索引来处理这个,所以这应该是一个简单的改变,特别是如果你像数组索引一样命名:

PositionData fourNearestPoints_0 = ...,
             fourNearestPoints_1 = ...,
             fourNearestPoints_2 = ...,
             fourNearestPoints_3 = ...;

接下来我要看的是_restPositions 的用法;我不知道GetLength(在此使用中)是否会被优化,所以我会尝试预先缓存它。在线性数组中,.Length 被优化(至少在完整的 CLR 中) - 但不是 GetLength AFAIK:

int width = _restPositions.GetLength(0), height = _restPositions.GetLength(1);
for (int x = 0; x < width; x++)
{
    for (int y = 0; y < height; y++)

还有; PositionData 是什么? struct 还是 class?我很想尝试这两者 - 确保它是不可变的,并通过构造函数传递数据以使 IL 更苗条:

PositionData temp = new PositionData(x, y, _restPositions[x,y],
        (linearPosition - _restPositions[x,y]).Length());

在下文中,您正在做一些大部分时间都被丢弃的工作:

    PositionData temp = new PositionData
    {
        indexX = x,
        indexY = y,
        value = _restPositions[x,y],
        distance = (linearPosition - _restPositions[x,y]).Length()
    };
    if (temp.distance < fourNearestPoints[0].distance)
    {
        fourNearestPoints[3] = fourNearestPoints[2];
        fourNearestPoints[2] = fourNearestPoints[1];
        fourNearestPoints[1] = fourNearestPoints[0];
        fourNearestPoints[0] = temp;
    }

我愿意:

var distance = (linearPosition - _restPositions[x,y]).Length();
if (distance < fourNearestPoints_0.distance) {
    fourNearestPoints_3 = fourNearestPoints_2;
    fourNearestPoints_2 = fourNearestPoints_1;
    fourNearestPoints_1 = fourNearestPoints_0;
    fourNearestPoints_0 = new PositionData(x, y, _restPositions[x,y], distance);
}

我也对distance=... 行感兴趣;那里有很多我们看不到的可能需要更多的工作 - - 运算符和 Length() 方法。


我是否正确假设 Length() 涉及平方根? (昂贵)您可以通过在平方距离内工作来避免这种情况。您可能需要使用不取根的平方长度方法来明确这一点,并在整个过程中比较平方长度,但您可以节省大量 CPU 周期。这是LengthSquared()

【讨论】:

  • 我最初将它作为结构,但更改为密封类将性能提高了 125%!如果只进行一次调用,将 GetLength 调用分离到变量中会有帮助吗?
  • 将数组分成 4 个变量并没有帮助。
  • GetLength(0) 被称为“行 + 1”。 GetLength(1) 每行被调用“cols + 1”次。因此,如果您的数组是 10x10,则为 11 + (10 * 11),即 121 次。
  • 哇,这也是个大问题。我马上把它分开。至于 - 运算符和 .Length() 调用,这些只是标准的 XNA Vector2 操作,您应该能够在使用 Reflector 或其他东西的那些上获得一些东西。我从来不知道什么是最快的....
  • 实际上有一个 LengthSquared 内置函数,我根据你的建议切换到它,它与你的其他一些组合将它提高了 100%。我现在要做一些分析,看看什么是最大的时间消耗,稍后再回来。
【解决方案2】:

一方面,请尝试对_restPositions 使用一维数组而不是矩形数组 - CLR 针对从零开始的一维数组进行了优化。只需在数组中保留一个索引,并在每次迭代时递增它:

int index = 0;
// I'm assuming you can pass in width and height separately
for (int x = 0; x < width; x++)
{
    for (int y = 0; y < height; y++)
    {
        PositionData temp = new PositionData
        {
            indexX = x,
            indexY = y,
            value = _restPositions[index],
            distance = (linearPosition - _restPositions[index]).Length()
        };
        if (temp.distance < fourNearestPoints[0].distance)
        {
            fourNearestPoints[3] = fourNearestPoints[2];
            fourNearestPoints[2] = fourNearestPoints[1];
            fourNearestPoints[1] = fourNearestPoints[0];
            fourNearestPoints[0] = temp;
        }
        index++;
    }
}

如果您可以为 PositionData 创建一个构造函数,它采用适当的值而不是使用单独的属性设置器,那可能也有帮助。

您还多次索引fourNearestPoints - 有什么理由不只使用四个局部变量?它不会做太多,但你永远不知道......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-18
    • 2011-06-06
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多