Lua性能优化的好文章

作者:陈劲灿 编辑日期: 2017年4月1日 11:32 阅读量: 434 分类: program

今天看到一篇关于Lua性能优化的文章感觉讲解的很好,于是赶紧记录下来,原文出处在这里http://www.lua.org/gems/sample.pdf

我挑一些重点出来讲解:

Use Locals (尽量使用局部变量)

先看个例子:

1.
2.
3.
for i = 1, 1000000 do
    local x = math.sin(i)
end
1.
2.
3.
4.
local sin = math.sin
for i = 1, 1000000 do
    local x = sin(i)
end
 1.
 2.
 3.
 4.
 5.
 6.
 7.
 8.
 9.
10.
11.
12.
13.
14.
15.
16.
17.
local t1 = os.clock()
for i = 1, 1000000 do
    local x = math.sin(i)
end
local t2 = os.clock()
print(t2 - t1)

local sin = math.sin
for i = 1, 1000000 do
    local x = sin(i)
end
local t3 = os.clock()
print(t3 - t2)

0.23
0.16
[Finished in 0.4s]

上面的函数每一个都需要调用math.sin,而下面函数保存成一个局部的变量后速度快了30%。

Lua Table构造的细节

先来看看下面这段代码在lua中的实现细节: Lua 的表由两个部分组成array部分、hash部分,

Lua需要向表中添加一个新的键,但哈希数组已满时,Lua将会重新哈希。重新哈希的第一步是决定新的数组部分和哈希部分的大小。Lua遍历所有的元素,计数并对其进行归类,然后为数组部分选择一个大小,这个大小相当于能使数组部分超过一半的空间都被填满的2的最大的幂;然后为哈希部分选择一个大小,相当于正好能容纳哈希部分所有元素的2的最小的幂。

先来看看两段代码:

1.
2.
3.
4.
for i = 1, 1000000 do
    local a = {}
    a[1] = 1; a[2] = 2; a[3] = 3
end
1.
2.
3.
4.
for i = 1, 1000000 do
    local a = {true, true, true}
    a[1] = 1; a[2] = 2; a[3] = 3
end
 1.
 2.
 3.
 4.
 5.
 6.
 7.
 8.
 9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
local t1 = os.clock()
for i = 1, 1000000 do
    local a = {}
    a[1] = 1; a[2] = 2; a[3] = 3
end
local t2 = os.clock()
print("1=" .. t2 - t1)

for i = 1, 1000000 do
    local a = {true, true, true}
    a[1] = 1; a[2] = 2; a[3] = 3
end
local t3 = os.clock()
print("2=" .. t3 - t2)

1=0.68
2=0.27
[Finished in 1.0s]

试试运行然后比较一下他们的运行时间. 为什么第二段代码会比第一段代码的运行时间短,这和Lua表的构造有关。Lua需要向表中添加一个新的键,但哈希数组已满时,Lua将会重新哈希。所以第一段代码触发了三次rehash ,既需要调整array部分的大小,也需要调整hash部分的大小。第二段代码在一开始即指定数组大小为4(2的整数幂),改变的不过是hash部分的大小。

表的中array以及hash部分的大小只有在rehash的时候才会被改变,所以当不需要此表的时候需要把表给nil掉,以便清除占用。

Lua String的拼接
降低表的使用频率
1.
2.
3.
4.
5.
polyline = { { x = 10.3, y = 98.5 },
{ x = 10.3, y = 18.3 },
{ x = 15.0, y = 98.5 },
...
}

可以看到上面代码每一行包含以个小表

1.
2.
3.
4.
5.
polyline = { { 10.3, 98.5 },
{ 10.3, 18.3 },
{ 15.0, 98.5 },
...
}

可以看出每一行也是一个小表,不过在构造的时候可以省一点内存。参考上面表的构造。

1.
2.
3.
polyline = { x = { 10.3, 10.3, 15.0, ...},
y = { 98.5, 18.3, 98.5, ...}
}

好的现在只需要构造两个表了。可以节省内存,不过需要改变表的读取方式。

降低循环中的各种表的构造
 1.
 2.
 3.
 4.
 5.
 6.
 7.
 8.
 9.
10.
11.
12.
13.
14.
15.
function foo (...)
for i = 1, n do
        local t = {1, 2, 3, "hi"}
        -- do something without changing ’t’
        ...
    end
end

local t = {1, 2, 3, "hi"}   -- create ’t’ once and for all
function foo (...)
    for i = 1, n do
        -- do something without changing ’t’
        ...
    end
end

可以看当上面的两个方式,第二中可以减少t 表在循环中的构造。

 1.
 2.
 3.
 4.
 5.
 6.
 7.
 8.
 9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
function changenumbers (limit, delta)
    for line in io.lines() do
        line = string.gsub(line, "%d+", function (num)
            num = tonumber(num)
            if num >= limit then return tostring(num + delta) end
            -- else return nothing, keeping the original number
        end)
        io.write(line, "\n")
    end
end

function changenumbers (limit, delta)
    local function aux (num)
        num = tonumber(num)
        if num >= limit then return tostring(num + delta) end
    end
    for line in io.lines() do
        line = string.gsub(line, "%d+", aux)
        io.write(line, "\n")
    end
end

可以看到第二个函数减少了匿名函数的构造。

其他方式

上一篇
下一篇
一行Python代码实现简单HTTP服务器
游戏中的碰撞检测算法