Lua5.4新特性
Lua5.4已经发布正式版。这个版本在语言层面上修改的东西并不多,但是默认的GC被换成了“分代式GC”,这对于那些经常产生短期对象的程序应该会有很明显的性能提升。GC带来的负担永远是自动内存管理语言的一大痛点,如果能在这一点上取得突破,那肯定比提供更多语法糖来得有价值。
此外5.4可以指定局部变量的属性,用这样的语法:
local a <NAME> = 3
NAME可以是const
或close
,为const时表示const变量(const variables
),const变量可以帮助编译器作一些优化,比如下面的代码:
local a <const> = 4
local b = a + 7
print(b)
编译器会把a消除掉,直接给b赋11。这种优化是有限的,对于基本类型和字符串,能够有效减少寄存器
的访问,但对于table貌似益处不大。代码文件如果需要一些数值常量,可以写成const变量,比如:
local MAX_LEN <const> = 20
function check_name(name)
return #name <= MAX_LEN
end
在check_name
中就没有upvalue的访问,而是直接转换成和20的比较。
close变量(To-be-closed Variables
)需要和close元方法结合使用,在变量超出作用域时,会调用变量的close元方法,这听起来是不是有点像C++的RAII用法。下面是一个例子:
local function newlock()
local lock = {
acquire = function()
print("acquire lock")
end,
release = function()
print("release lock")
end,
}
return lock
end
local function lockguard(lock)
local wrap = {
lock = lock
}
lock.acquire()
return setmetatable(wrap, {__close = function(t, err)
t.lock.release()
end})
end
local lock = newlock()
do
for i = 1, 3 do
local l <close> = lockguard(lock)
print(i)
error("err")
end
end
定义local l <close>
后,无论是否有错误,release都能得到调用;从这个例子也可以看出,close变量一般用于需要及时释放资源的情况;否则Lua的GC可以应付大多数情况。
除了上面提到的特性,还有一些新的修改如下:
- userdata现在可以关联多个user值,C的API也有相应的修改,如果我们新建的userdata没有关联值,则尽量使用
lua_newuserdatauv
,这样更高效,lua_newuserdata
仅仅为了兼容,且默认会关联1个值。 - math.random使用了新的算法(基于xoshiro256**);并且会从随机的种子开始,使程序启动后第1次调用math.random会得到不同值。
- 协程库提供了新的API
coroutine.close
和lua_resetthread
,coroutine.close
只能在挂起或死亡状态下调用,挂起状态下会使用协程进入死亡状态,并且关闭所有的close变量。
当然这些是明面上的修改,其实内部现实作了大量的优化,使得这个版本的性能比之前提高了40%左右,下面是我在阅读代码中的一些发现:
- table的哈希node占用内存变小了,只需要24个字节;以前版本需要32个字节,这得使Lua的内存占用显著的减少。
- table优化了数组部分的实现,使得#t的效率提高了数倍之多。
- 函数原型的debug信息,优化了指令到代码行映射的内存占用,小的函数可以减少差不多3倍的内存。
- luaV_execute在GNU下使用GCC的扩展(Labels as Values)实现更快的指令分派,从而优化VM的执行效率。
- 虚拟机指令更加细化,这些细化都是为了提高VM的操作效率,比如加载指令增加了立即数的类型,这样就不必将立即数保存为常量,而是直接在指令中取就可以。具体的性能测试见这个文章。
编辑于 2021-06-24 09:57