Lua性能优化
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表是否为空。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |