Lua代码优化方案

       

目录

一.使用局部变量

二.尽可能避免在lua程序中编译代码

三.table优化


 lua作为脚本语言,大量应用于游戏开发。那lua代码的优化就变得非常重要。本文就从本人从事项目中的优化进行阐述,并参考一些文章的书籍。

        lua以其性能而闻名,那lua的代码需要优化吗,答案是肯定的。但进行优化时总要应该有一些衡量,要知道哪里最优,然后进行度量,以了解优化的过程是否确实改进了我们的代码。

        基本事实在运行任何代码之前,Lua会将源代码转换(预编译)为内部格式。这种格式是虚拟机的指令序列,类似于真实CPU的机器码。然后,这个内部格式由C代码解释,它本质上是一个while循环,内部有一个大开关,每个指令有一个case。

        也许您已经了解到,自5.0版本以来,Lua使用了一个基于寄存器的虚拟机。这个虚拟机的“寄存器”与CPU中的实际寄存器不对应,因为这种对应是不可移植的,而且可用寄存器的数量非常有限。相反,Lua使用堆栈(实现为数组加上一些索引)来容纳它的寄存器。每个活动函数都有一个激活记录,它是一个堆栈片,函数在其中存储它的寄存器。因此,每个函数都有自己的寄存器。每个函数可以使用多达250个寄存器,因为每条指令只有8位寄存器。

        考虑到大量寄存器,Lua预编译器能够将所有本地变量存储在寄存器中。结果是Lua中对局部变量的访问非常快。例如,如果a和b是局部变量,像a= a + b这样的Lua语句会生成一条指令:ADD 0 0 1(假设a和b分别在寄存器O和1中)。作为比较,如果a和b都是全局变量,那么加法的代码如下所示:

        GETGLOBAL 0 0 ; a

        GETGLOBAL 1 1 ; b

        ADD 0 0 1

        SETGLOBAL 0 0 ; a

一.使用局部变量

例如1:for i = 1, 1000000 do

        local x = math.sin(i)

end

这边方法就比下面慢了30%

local sin = math.sin

for i = 1, 1000000 do

        local x = sin(i)

end

并且注意:访问外部局部变量(即封闭函数的局部变量)不如访问局部变量快,但仍然比访问全局变量快。

二.尽可能避免在lua程序中编译代码

        例如使用loadstring(将一个table类型的字符串 转换成table)

        举个例子:

        local lim = 10000

        local a = {}

        for i = 1, lim do

                a[i] = loadstring(string.format("return %d", i))        

         end

        print(a[10]()) --> 10 --代码运行时间为1.4s

        使用闭包可以加快运行速度:

        function fk (k)

                return function () return k end

         end

        local lim = 100000

        local a = {}

        for i = 1, lim do

                a[i] = fk(i)

        end

        print(a[10]()) --> 10

三.table优化

        lua的表是lua特色的地方,因此,要优化使用表的程序(实际上是任何Lua程序),最好了解一点Lua如何实现表。

        Lua中的表的实现涉及到一些巧妙的算法。Lua中的每个表都有两个部分:数组部分和散列部分。数组部分存储在1到n范围内的整数键条目,用于特定的n(我们稍后将讨论如何计算这个n)。所有其他条目(包括该范围之外的整数键)都转到散列部分。

        顾名思义,散列部分使用散列算法来存储和查找其键。它使用所谓的开放地址表,这意味着所有条目都存储在哈希数组本身。哈希函数给出一个键的主索引;如果存在冲突(也就是说,如果两个键被散列到相同的位置),这些键将链接到一个列表中,每个元素占用一个数组条目。

        当Lua需要向表中插入一个新键,而散列数组已满时,Lua会进行重新散列。重新散列的第一步是确定新数组部分和新散列部分的大小。因此,Lua遍历所有条目,对它们进行计数和分类,然后选择数组部分的大小为2的最大次方,这样数组部分的一半以上的元素都被填充了。哈希大小是2的最小次方,它可以容纳所有剩余的条目(即那些没有适合数组部分的条目)。当Lua创建一个空表时,这两个部分的大小都是O,因此没有为它们分配数组。让我们看看当我们运行以下代码时会发生什么:

        local a = {}

        for i = 1, 3 do

                a[i] = true

        end

        首先创建一个空表a。在第一次循环迭代中,赋值a [1] =true触发了一次散列;然后,Lua将表中数组部分的大小设置为1,并保持散列部分为空。在第二次循环迭代中,赋值a [2] =true触发了另一次重散列,因此现在表的数组部分的大小为2。最后,第三次迭代触发了另一次重散列,将数组部分的大小增加到4。

        但是如果改成这样:

        a = {}

        a.x = 1; a.y = 2; a.z =3 --那么只增长了表的哈希部分

因此在编程过程中,可以使用构造函数来避免这些初始的重复哈希。

        未完待续、、、、

猜你喜欢

转载自blog.csdn.net/qq_34263160/article/details/126590391