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*y+z*z);
end;
-- 例如: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性能提示吗?
原文链接 https://stackoverflow.com/questions/6257148
真的吗?
运行 800 个这样的计算不应该超过 0.001 秒——即使在手机上使用 Lua。
您是否进行了一些性能分析以查看它是否真的会减慢您的速度?您是否用“return(0)”替换了该函数以验证性能是否有所提高(是的,函数将丢失)。
您确定它是每秒而不是每毫秒运行?
自 1987 年以来,我还没有见过在 1 秒钟内运行 800 个简单的任何东西的问题。
你应该阅读罗伯托·耶鲁萨利姆斯基(Lua 的首席架构师)的Lua 性能技巧。它涉及一些你所询问的小优化(例如将库函数本地化和用它们的乘法等价物替换指数)。最重要的是,它传达了工程中最重要但常被忽视的思想之一:有时改变问题是最好的解决方案。通过减少计算所需的 CPU 周期,你无法修复 3000 万次计算泄漏。
对于你特定的距离计算案例,你会发现最好让你的基础计算返回表示平方距离的中间和,而允许使用案例仅在需要时调用最终的勾股定理步骤,这通常是不需要的(例如,你不需要执行平方根操作来比较两个平方长度哪个更长)。
然而,在讨论优化之前,你应该考虑此问题:不要担心不是“问题”的问题。与其搜寻你代码中任何“可能”的问题,直接解决最“大”的问题。如果性能超过缺失功能、错误和/或用户体验缺陷并成为你最突出的瓶颈语句,那么微小的低效率很难累积到超过这个瓶颈。
正如引用文章开头所述:
在 Lua 中,就像在任何其他编程语言中一样,我们应该始终遵循两个最大化程序的优化规则:
规则 # 1: 不要这样做。
规则 # 2: _还不要这样做。_(仅适用于专家)
如果你想计算正数a
的平方根,则采用递归序列
x_0 = a
x_n+1 = 1/2 * (x_n + a / x_n)
当n -> infinity
时,x_n
趋近于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 |
+---------+--------------+
如果你一直在“所有东西都与所有东西进行比较”,你的算法将会成二次复杂度地增长。
优化你的代码最好的选择并不是“微调”数学操作或使用本地变量而不是引用。
真正推动你的算法的事情将是消除你不需要的计算。
最显而易见的例子就是如果你已经计算出Player2与Player1的距离,那么就不要再计算Player1和Player2之间的距离。这个简单的优化应该能将你的时间减少一半。
另一个非常常见的实现方法是将空间分为“区域”。当两个对象在同一区域内时,你正常计算它们之间的距离。当它们在不同的区域内时,你则使用近似值计算。理想的空间分割方式将取决于你的环境;一个例子是将空间分割成网格,在不同方格的玩家之间,使用他们方格中心之间的距离,这个你预先计算过)。
有一整个编程分支正在处理这个问题;它被称为空间划分。看看这个:
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
我真的怀疑这些微小的优化是否真的有所帮助。你应该专注于你的算法,比如通过修剪消除一些距离计算,停止计算用于比较的数值的平方根(提示:如果
a^2
<b^2
并且a
>0 且b
>0,则a
<b
),等等。