Performance Lua:代码优化向量长度计算

Performance Lua:代码优化向量长度计算,performance,math,optimization,lua,Performance,Math,Optimization,Lua,我在游戏中有一个脚本,其中有一个函数每秒都会被调用。玩家对象和其他游戏对象之间的距离每秒计算一次。问题是在1秒内可以有800个函数调用(最多40个玩家*2个主要对象(1到10个子对象))。我必须优化此函数以减少处理。这是我目前的职能: local square = math.sqrt; local getDistance = function(a, b) local x, y, z = a.x-b.x, a.y-b.y, a.z-b.z; return square(x*x+y

我在游戏中有一个脚本,其中有一个函数每秒都会被调用。玩家对象和其他游戏对象之间的距离每秒计算一次。问题是在1秒内可以有800个函数调用(最多40个玩家*2个主要对象(1到10个子对象))。我必须优化此函数以减少处理。这是我目前的职能:

local square = math.sqrt;

local getDistance = function(a, b)
    local x, y, z = a.x-b.x, a.y-b.y, a.z-b.z;
    return square(x*x+y*y+z*z);
end;

-- for example followed by: for i = 800, 1 do getDistance(posA, posB); end
我发现math.sqrt函数的本地化是通过

local square = math.sqrt;
在速度和代码方面是一个很大的优化

x*x+y*y+z*z
比此代码快:

x^2+y^2+z^2
我不知道x、y和z的本地化是否比使用class方法“两次”要好,所以可能
square(a.x*b.x+a.y*b.y+a.z*b.z)
比code
local x,y,z=a.x-b.x,a.y-b.y,a.z-b.z更好;
正方形(x*x+y*y+z*z)


有没有更好的数学方法来计算向量长度,或者Lua中有更多的性能提示?

我真的怀疑这些微优化是否真的有用

你应该把注意力集中在你的算法上,比如,通过剪枝去掉一些距离计算,停止计算值的平方根进行比较(提示:如果
a^2
0和
b
>0,那么
a
真的吗

运行其中的800次计算不应超过0.001秒——即使是在手机上的Lua中

您是否进行了一些分析以查看它是否真的会减慢您的速度?是否将该函数替换为“return(0)”以验证性能是否有所提高(是的,函数将丢失)

你确定它每秒钟运行一次,而不是每毫秒运行一次吗


自1987年以来,我从未见过一个简单的问题在1秒内运行800次。

您应该阅读Roberto Ierusalimschy的(Roberto是Lua的首席架构师)。它涉及到您正在询问的一些小优化(例如本地化库函数并用其多复制等价物替换指数)。最重要的是,它传达了工程中最重要和被忽视的思想之一:有时,最好的解决方案包括更改您的问题。您不会通过减少计算所需的CPU周期来修复3000万次计算泄漏

在距离计算的特定情况下,您会发现最好让原始计算返回表示平方距离的中间和,并允许用例仅在需要时调用最终的毕达哥拉斯步骤,而他们通常不需要(例如,您不需要执行平方根来比较两个平方长度中哪一个更长)

不过,这确实应该摆在任何优化讨论之前:不要担心那些不是问题所在的问题。与其在代码中寻找任何可能的问题,不如直接着手解决最大的问题——如果性能超过了最引人注目的iss缺少的功能、bug和/或UX缺陷事实上,微观效率几乎不可能累积到超过单一瓶颈声明的程度

或者,如引用文章开头所述:

在Lua中,就像在任何其他编程语言中一样,我们应该始终遵循这两个原则 程序优化准则:

规则1:不要这样做

规则#2:先不要做。(仅限专家)


如果要计算正数
a
的sqrt,请采用递归顺序

x_0 = a
x_n+1 = 1/2 * (x_n + a / x_n)
xn
使用
n->infinity
进入
sqrt(a)
。前几次迭代应该足够快

顺便说一句,也许你会尝试使用下面的公式来计算向量的长度,而不是标准的长度

local getDistance = function(a, b)
    local x, y, z = a.x-b.x, a.y-b.y, a.z-b.z;
    return x+y+z;
end;
计算起来要容易得多,在某些情况下(例如,如果需要距离来确定两个物体是否接近),它可能起到足够的作用。

您的“暴力”方法无法很好地扩展

我的意思是,系统中包含的每个新对象/播放器都会显著增加操作数量:

 +---------+--------------+
 | objects | calculations |
 +---------+--------------+ 
 |      40 |        1600  |
 |      45 |        2025  |
 |      50 |        2500  |
 |      55 |        3025  |
 |      60 |        3600  |
...       ...            ...
 |     100 |       10000  |
 +---------+--------------+
如果你一直比较“一切与一切”,你的算法将开始以一种不规则的方式占用越来越多的CPU周期

优化代码的最佳选择不是“微调”数学运算或使用局部变量而不是引用

真正提升算法的是消除不需要的计算

最明显的例子是,如果您已经计算了Player2和Player1之间的距离,则不计算Player1和Player2之间的距离。这个简单的优化应该将您的时间减少一半

另一种非常常见的实现方式是将空间划分为“区域”。当两个对象位于同一区域时,您通常会计算它们之间的空间。当它们位于不同区域时,您会使用近似值。分割空间的理想方式将取决于您的上下文;例如,将空间划分为网格,对于位于不同正方形上的玩家,使用其网格中心之间的距离平方,即您预先计算的)

编程中有一个完整的分支处理这个问题;它被称为空间分区。请看一下:


我在某个地方读到math.sqrt是一个昂贵的操作。如果我得到800个函数调用,我应该优化我的函数-这是我的想法。我不是数学专业的学生,你想如何去掉带有“a^20和b>0,然后是a”的正方形(他说的是让函数返回平方距离,如果需要的话让调用者执行平方根操作——他们通常不这样做,因为他们只是在执行比较,并且(sqrt(a)