加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Lua性能优化

发布时间:2020-12-14 22:09:11 所属栏目:大数据 来源:网络整理
导读:LuaJIT本身对Lua作了很多方面的优化工作,对很多Lua自带的库函数进行了优化。 优化详情:http://wiki.luajit.org/NYI wiki:http://wiki.luajit.org/Home 关于Lua优化的一些细节: 1 .经常使用的库函数,使用local方式来调用,注意仅一次调用是不起作用的。 -

LuaJIT本身对Lua作了很多方面的优化工作,对很多Lua自带的库函数进行了优化。

优化详情:http://wiki.luajit.org/NYI

wiki:http://wiki.luajit.org/Home


关于Lua优化的一些细节:


1.经常使用的库函数,使用local方式来调用,注意仅一次调用是不起作用的。

--this?is?the?lowest?method
????string.rep()

--this?is?a?better?way
????local?rep?=?string.rep

2.创建table时,事先分配好大小。

--allocate?the?table?when?you?declare?it
????local?tbl?=?{nil,nil}
????table.insert(tbl,1)
????table.insert(tbl,2)

lua table的内存分配按照2的N次方递增,所以在不断table.insert的过程中,会在前期频繁的申请内存空间因此事先申请好内存能够提升性能。


3.避免一些长字符串的format操作,长字符串的format操作效率低下,对于长字符串可以考虑使用..操作来进行字符串连接,效率比format高。

local?str?=?[==[?hello?%s?]==]
string.format(str,"world")

local?str?=?[[hello]]
return?str..?"world"


4.一个文件中的函数尽量使用local方式来定义

????local?plus?=?function(a,b)
????????return?a+b
????end

5.一些结构的优化。这里我们定义了一个Filter,其中有typeA和typeB 2种类型的filter,遍历这些filter,我们有3种方式封装API:

????

--now?we?define?a?filter
--we?get?three?ways?to?define?it

---all?filters?listed
local?Filter?=?{nil,nil}
local?Filter.typeA?=?{nil,nil}
local?Filter.typeB?=?{nil,nil}


Filter.typeA.filter1?=?function()
end

Filter.typeA.filter2?=?function()
end

Filter.typeB.filter1?=?function()
end?

Filter.typeB.filter2?=?function()
end

--first?way
function?handler(arg)
????if?not?Filter.typeA.filter1()?then
????????return?false
????end
????
????if?not?Filter.typeA.filter2()?then
????????return?false
????end
????
????if?not?Filter.typeB.filter1()?then
????????return?false
????end
????
????if?not?Filter.typeB.filter2()?then
????????return?false
????end
????
????return?true
end?

--second?way
function?handler(arg)
????for?k,func?in?pairs(Filter.typeA)?do
????????if?not?func()?then
????????????return?false
????end
???
????for?k,func?in?pairs(Filter.typeB)?do
????????if?not?func()?then
????????????return?false
????????end
????end
????
????return?true
end

--third?way
local?func_name_list?=?{?'filter1','filter2'}

function?handler(arg)
????for?_,name?in?ipairs(func_name_list)?do
????????if?not?Filter.typeA[name]()?then
????????????return?false
????????end
????????
????????if?not?Filter.typeB[name]()?then
????????????return?false
????????end
?????end

?????return?true
end


--fourth?way
local?typeA_func_list?=?{
?????????????????????????????Filter.typeA.filter1(),?????????????????????????????Filter.typeA.filter2()???????????????????
????????????????????????}
????????????????????????
local?typeB_func_list?=?{
?????????????????????????????Filter.typeB.filter1(),?????????????????????????????Filter.typeB.filter2()
????????????????????????}
function?handler(arg)
????for?_,func?in?ipairs(typeA_func_list)?do
????????if?not?func()?then
????????????return?false
????????end
????end
????
????for?_,func?in?ipairs(typeB_func_list)?do
????????if?not?func()?then
????????????return?false
????????end
????end
????
????return?true
end

这里值得注意的是,LuaJIT针对ipairs作了相当的优化,但是对于pairs,LuaJIT中没有作优化,在一些table中我们尽量避免使用hash表,遍历的时候使用iparis。

第一种方式是效率最高的,但是结构很糟糕,代码维护起来比较难。

第二种方式遍历效率极低。

第三种效率不错,代码结构一般。

第四种是最好的遍历方式,结构也很不错。我们采用这种方式是最优的。


6.关于table的遍历


在LuaJIT中针对ipairs作了相当的优化,但是对pairs没有优化。另外对于一些遍历,尽量使用for i,#table do end 来进行遍历。LuaJIT中针对for遍历也进行了优化。对于数组尽量使用for来遍历,这是最快的遍历方式。


7.关于config的加载,首先看测试脚本

--?conf_table.lua
???
???local?conf_table?=?{nil,nil,nil}?
???
???conf_table.A?=?"string?A"
???conf_table.B?=?"string?B"
???conf_table.C?=?"string?C"
??
???return?conf_table
?--?conf_notbl.lua
?????
?????A?=?"string?A"
?????B?=?"string?B"
?????C?=?"string?C"
--?conf_test.lua
????require?'conf_notbl'
????local?conf?=?require?'conf_table'
????local?socket?=?require?'socket'
????local?round?=?10000000
????local?time?=?socket.gettime()
????for?i=1,round?do
????????local?x?=?A
????????local?y?=?B
????????local?z?=?C
????end
????print("conf?before?:"?..?(socket.gettime()-time)*1000?..?"ms")
????local?time?=?socket.gettime()
????for?i=1,round?do
????????local?x?=?conf.A
????????local?y?=?conf.B
????????local?z?=?conf.C
????end????
????print("conf?table??:"?..?(socket.gettime()-time)*1000?..?"ms")
????local?a1=A
????local?a2=B
????local?a3=C
????local?time?=?socket.gettime()
????for?i=1,round?do
????????local?x?=?a1
????????local?y?=?a2
????????local?z?=?a3
????end
????print("local?conf?:"?..?(socket.gettime()-time)*1000?..?"ms")??
测试结果:
Lua:
????conf?before?:742.80691146851ms
????conf?table??:789.02816772461ms
????local?conf?:403.17010879517ms
LuaJIT:
????conf?before?:4.1639804840088ms
????conf?table??:4.1368007659912ms
????local?conf?:3.9420127868652ms

在使用lua文件来加载config的时候,尽量使用local方式来将经常使用的conf的数据存起来,如果使用次数不多,这样做就没有必要了。

另外特意使用一个table来存储conf数据并没有必要,但是这样做config结构比较好。


8.关于table.insert

luajit中对于table.insert作了优化。对于数组类型的table,可以利用tbl[#tbl+1]的方式来进行赋值操作,直接用lua解释器可以看到明显的性能差距,用luajit的话差距就没有这么明显了。

local?tbl?=?{}
table.insert(tbl,1)
tbl[#tbl+1]?=?1
--运行1000000次的结果
Lua:
????table.insert?time?:293.66397857666ms
????tbl[#tbl+1]?time?:186.48815155029ms
????local?insert?time?:222.85604476929ms??--添加了?local?insert?=?table.insert
LuaJIT:
????table.insert?time?:137.73202896118ms
????tbl[#tbl+1]?time?:134.56797599792ms
????local?insert?time?:137.2811794281ms

可以看到LuaJIT对于table.insert的操作作了优化,所以使用luajit时可以不必刻意使用tbl[#tbl+1]=1的方式来进行insert操作。另外LuaJIT对于local调用也作了优化。


9.对于数组table是否为空的判断

????尽量使用table.getn,对于hash表则必须使用next,table.getn不能判断hash表是否为空。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读