我在游戏中有一个脚本,每秒都会调用一个函数。在那里每秒计算玩家对象和其他游戏对象之间的距离。问题是在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的本地化是否优于使用类方法“。”两次,因此square(a.x*b.x+a.y*b.y+a.z*b.z)
可能比代码local x, y, z = a.x-b.x, a.y-b.y, a.z-b.z;
square(x*x+y*y+z*z);
在数学中有更好的方法来计算向量长度还是在Lua中有更多的性能提示?
答案 0 :(得分:8)
你应该阅读Roberto Ierusalimschy的Lua Performance Tips(Roberto是Lua的首席架构师)。它涉及您要询问的一些小优化(例如本地化库函数和用其多重等价替换指数)。最重要的是,它传达了工程中最重要和最被忽视的一个想法:有时候最好的解决方案就是改变你的问题。你不会通过减少数量来修复3000万计算泄漏计算所需的CPU周期数。
在您的距离计算的特定情况下,您会发现最好使原始计算返回表示平方距离的中间和并允许用例调用最后的毕达哥拉斯步骤只有当他们需要时,他们通常不会这样做(例如,你不需要执行平方根来比较两个平方长度中的哪一个更长)。
在讨论优化之前,这确实应该出现:不要担心不是 问题的问题。而不是搜索任何<的代码< em>可能的问题,直接跳转到修复最大的 - 如果性能超出了缺失的功能,错误和/或用户体验缺点导致最明显的问题,微观效率低下几乎不可能达到超越单一瓶颈声明的程度。
或者,正如所引用文章的开头所述:
在Lua中,和任何其他编程语言一样,我们应该始终遵循这两种语言 程序优化的格言:
规则#1: 不要这样做。
规则#2: 尚未执行此操作。(仅限专家)
答案 1 :(得分:3)
老实说,我怀疑这些微优化确实对任何人都有帮助。
你应该专注于你的算法,例如通过修剪去除一些距离计算,停止计算值的平方根进行比较(提示:如果a^2
&lt; b^2
和a
&gt; 0和b
&gt; 0,然后是a
&lt; b
)等等
答案 2 :(得分:2)
你的蛮力&#34;方法不能很好地扩展。
我的意思是系统中包含的每个新对象/播放器都会显着增加操作次数:
+---------+--------------+
| objects | calculations |
+---------+--------------+
| 40 | 1600 |
| 45 | 2025 |
| 50 | 2500 |
| 55 | 3025 |
| 60 | 3600 |
... ... ...
| 100 | 10000 |
+---------+--------------+
如果你继续比较&#34;所有内容和#34;,你的算法将开始以一种cuadratic方式占用越来越多的CPU周期。
优化代码的最佳选择并非在&#34;微调&#34;数学运算或使用局部变量而不是参考。
真正提升算法效果的将是消除您不需要的计算。
如果你已经计算了Player2和Player1之间的距离,那么最明显的例子就是不计算Player1和Player2之间的距离。这种简单的优化可以将您的时间减少一半。
另一个非常常见的实现方法是将空间划分为&#34; zone&#34;。当两个对象位于同一区域时,您可以正常计算它们之间的间距。当它们位于不同的区域时,您使用近似值。划分空间的理想方式取决于您的背景;一个例子是将空间划分为一个网格,对于不同方块的玩家,使用他们预先计算过的方块中心之间的距离。
在编程中处理这个问题的整个分支;它被称为空间分区。看看这个:
答案 3 :(得分:1)
真的?
运行800次这些计算的时间不应超过0.001秒 - 即使是手机上的Lua也是如此。
你做过一些分析,看看它是否真的让你失望?您是否用“return(0)”替换了该函数以验证性能是否提高(是的,函数将丢失)。
你确定它每秒运行一次而不是每毫秒运行一次吗?
自1987年以来,我没有看到在1秒钟内运行800的任何简单问题。
答案 4 :(得分:0)
如果您想对正数a
计算方法,请采用递归顺序
x_0 = a
x_n+1 = 1/2 * (x_n + a / x_n)
x_n
与sqrt(a)
一起转到n -> infinity
。前几次迭代应该足够快。
顺便说一句!也许你会尝试使用以下公式来确定标准的矢量长度。
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;
计算起来要容易得多,并且在某些情况下(例如,如果需要距离来知道两个物体是否接近),它可能就足够了。