这里记录下一些lua
使用优化操作。
堆栈溢出
我们在运行lua
的时候,有可能遇到这样一种报错 “stack overflow”,先看看下面一段代码:
1 | function func_r(a) |
语法上的确没有任何问题,但在执行的时候就会出现stack overflow
的报错。是什么原因导致堆栈溢出呢?这个就要追究到Lua
源码:Lua
虚拟机会对堆栈进行一系列的检查(函数:luaL_checkstack
),错误类型就有:
1 | “too many arguments”, |
例如,上面的代码就属于递归嵌套次数太多,默认限制20000。
不支持边遍历表边删除表中字段
当在遍历表的时候为不存在的字段赋值时,next
的遍历顺序是未知的,然而,你可以在遍历时修改已有的字段,或者,你可以删除已经存在的字段。
使用局部变量local
这是最基础也是最有用的策略,虽然使用全局变量并不能完全避免,但还是应该尽量避免,取而代之使用局部变量即local
。这里的局部变量也包括函数function
,因为在Lua
里函数也是一个变量。局部变量的存取会更快,而且在生命周期之外就会释放掉。
尾调用消除
Lua
中的函数调用有两种,一种是标准的函数调用,它会需要生成新的一层调用栈,执行函数流程,然后弹出调用栈返回。另一种叫做尾调用,它是对标准函数调用的优化。尾调用不生成新的调用栈,而不复用当前的。在大多数函数式编程语言中,都需要对尾调用做特别优化。因为函数式语言特别依赖函数的层层调用,甚至用尾调用的方式来做循环。传统方式每次函数调用都需要生成新的栈帧,容易造成栈溢出。 尾调用可以看作C
中的goto
。
当一个函数调用是另一个函数的最后一个动作时,该调用才算是一条“尾调用”。
1 | --尾调用 |
也就是说,当f
调用完g
之后就再无其他事情可做了。因此在这种情况中,程序就不需要返回那个“尾调用”所在的函数了。所以在“尾调用”之后,程序也不需要保存任何关于该函数的栈信息了。当g
返回时,执行控制权可以直接返回到调用f
的那个点上。使得在进行“尾调用”时不耗费任何栈空间。将这种实现称为支持“尾调用消除”。
传参时,少用…
…用于可变参数。如果在传参数过多时,为了方便使用…,会降低代码可读性(寻找参数)。
少用字符串连接操作符
从lua
字符串的实现可知,运用字符串连接操作符每一次都会生成一个新的字符串。可使用table
来模拟字符串缓冲区,避免了大量使用连接操作符。table.concat()
。
table使用预填充技术
Lua
解释器背着我们会对表进行重新散列的动作, lua Table新增元素有详细解释。一个整数的key
在同一个表中不同的阶段可能被分配到数组或者散列桶部分。
而这个操作的代价是挺大的。
如下面的代码:
1 | local a = {} |
最开始,Lua
创建了一个空表a
。在第一次迭代中,a[1]
为 true
触发了一次重新散列操作,Lua
将数组部分的长度设置为2^0
,即1
,散列表部分仍为空。在第二次迭代中,a[2]
为true再次触发了重新散列操作,将数组部分长度设为2^1
,即2
。最后一次迭代又触发了一次重新散列操作,将数组部分长度设为2^2
,即4。
只有三个元素的表会执行三次重新散列操作,然而有100万个元素的表仅仅只会执行20次重新散列操作而已,因为2^20 = 1048576 > 1000000。 但是,如果创建了非常多的长度很小的表(比如坐标点: point = {x=0, y=0}),这可能会造成巨大的影响。所以,当需要创建非常多的小表时,应预先填充好表的大小,减少解释器被动地进行重新散列操作的过程。
如果你有很多很小的表需要创建,就可以预先填充以避免重新散列操作。比如:{true, true,true},Lua
知道这个表有3个元素,所以直接创建了3个元素的数组。 类似地,{ X=l, y=2, z=3,},Lua
会在其散列表部分中创建长度为3的数组。
所以,上述代码使用了预填充技术为:
1 | local a = {1,2,3} |
限制require到别的模块
手工编写服务表,防止require
到别的服务的lua
模块
REQUIRE_CHECK_LIST = {
[“A”] = true,
[“B”] = true,
}
1 | local realrequire = require |
将全局函数首先加载到局部变量中
从局部变盘和全局变量的获取来看,如果针对的是全局变量,那么会比局部变量额外多一条GETGLOBAL
指令,用于将这个全局变量加载到当前函数栈中。因此,一个经常使用的全局变量,可以优化为首先加载到一个局部变量中,再针对这个局部变量进行使用。
1 | for i = 1,10000000 do |
使用局部变量优化:
1 | local sin = math.sin |