lua programming skills and optimizations

52
Lua Lua 基基基基基基基基基 基基基基基基基基基 http://kimbs.cn http://kimbs.cn

Upload: ho-kim

Post on 15-Jan-2015

349 views

Category:

Technology


16 download

DESCRIPTION

Lua Programming Skills and Optimizations

TRANSCRIPT

Page 1: Lua Programming Skills and Optimizations

LuaLua 基础技巧与性能优基础技巧与性能优化化

http://kimbs.cnhttp://kimbs.cn

Page 2: Lua Programming Skills and Optimizations

Lua Lua 基础技巧基础技巧

Page 3: Lua Programming Skills and Optimizations

Lua Lua 程序块程序块LuaLua 程序可以分为:程序可以分为:11 )控制结构的执行体)控制结构的执行体 (if … else …)(if … else …)

22 )函数执行体()函数执行体( doFunction()doFunction() ))33 )程序块()程序块( do ...... enddo ...... end ))

Page 4: Lua Programming Skills and Optimizations

三元运算三元运算三元运算:三元运算:local a = 2 > 1 and “aa” or “bb”local a = 2 > 1 and “aa” or “bb”

Page 5: Lua Programming Skills and Optimizations

大小写敏感大小写敏感and and 是保留字是保留字

但是 但是 And And 和 和 AND AND 则不是 则不是 Lua Lua 的保留字的保留字

Page 6: Lua Programming Skills and Optimizations

For For 循环循环泛型:泛型:for i, v in pairs(t) dofor i, v in pairs(t) do

print(v)print(v)

endend

数字型:数字型:for i = 1, N dofor i = 1, N do

......

endend

Page 7: Lua Programming Skills and Optimizations

注释注释单行注释:单行注释:-- -- 被注释的行被注释的行

多行注释:多行注释:--[[--[[

技巧:只需在前面加一个 技巧:只需在前面加一个 - - 就可以重启本段代码了就可以重启本段代码了--]]--]]

Page 8: Lua Programming Skills and Optimizations

变量赋值变量赋值a = 1 b = 2 c = 3a = 1 b = 2 c = 3

-- -- 可以。。。但相当难看可以。。。但相当难看

a = 1a = 1

b = 2b = 2

c = 3c = 3

-- -- 最好是分行最好是分行

Page 9: Lua Programming Skills and Optimizations

默认值默认值设置默认值的方法设置默认值的方法 ::

local x = x or defaultValuelocal x = x or defaultValue

Page 10: Lua Programming Skills and Optimizations

局部(局部( locallocal )变量)变量11 )只作用于当前程序块)只作用于当前程序块22 )安全)安全33 )访问比全局变量快)访问比全局变量快44 )内存回收及时)内存回收及时

Page 11: Lua Programming Skills and Optimizations

变量类型变量类型11 )) Lua Lua 是弱类型语言是弱类型语言

22 )很多时候都要使用 )很多时候都要使用 type() type() 来判断变量类型来判断变量类型

33 )熟练运用 )熟练运用 type type 是避免是避免 bugbug 的有效手段的有效手段

Page 12: Lua Programming Skills and Optimizations

删除变量删除变量a = nila = nil

Page 13: Lua Programming Skills and Optimizations

保留字保留字以 下划线以 下划线 ++ 字符 组成的变量都是 字符 组成的变量都是 Lua Lua 保留标识符保留标识符尽量不用这样的变量命名方式尽量不用这样的变量命名方式

例如 例如 _NAME, _M, _G, … _NAME, _M, _G, … 等等等等

Page 14: Lua Programming Skills and Optimizations

字符串下标字符串下标String String 的下标(的下标( indexindex )是从)是从 11 开始,而不是开始,而不是 00

string.sub(“hhelloo”,2,-2) -- hellostring.sub(“hhelloo”,2,-2) -- hello

Page 15: Lua Programming Skills and Optimizations

字符串长度字符串长度 str = “hello”str = “hello”

print(#str)print(#str)

注意:注意: # # 返回的只是线性表最后一个索引值,在 返回的只是线性表最后一个索引值,在 table table 中间有空隙(中间有空隙( nilnil )的情况下,就不靠谱)的情况下,就不靠谱了。了。

Page 16: Lua Programming Skills and Optimizations

字符串连接字符串连接连接符号连接符号““ ..”..” 的陷阱的陷阱

print(123.. 456) -- print(123.. 456) -- 报错报错print(123 .. 456) -- print(123 .. 456) -- 字符串“字符串“ 123456”123456”

Page 17: Lua Programming Skills and Optimizations

空字符串空字符串数字数字 0 0 和 空字符串 在条件判断中都视为“真”!和 空字符串 在条件判断中都视为“真”!

类似 类似 PHP PHP 的经典错误的经典错误 if (empty(‘’)) if (empty(‘’)) 不会再现不会再现

Page 18: Lua Programming Skills and Optimizations

字符串格式化字符串格式化string.format("%02d/%02d/%04d", d, m, y) string.format("%02d/%02d/%04d", d, m, y) 

-- 05/11/1990-- 05/11/1990

跟跟 CC 语言里面的 语言里面的 printf printf 用法基本相同用法基本相同

Page 19: Lua Programming Skills and Optimizations

字符串修改字符串修改String String 是不可变值,修改实际上是“重新组装”是不可变值,修改实际上是“重新组装”

s2 = string.gsub(s1, 'before', 'after');s2 = string.gsub(s1, 'before', 'after');

-- s1 -- s1 的值不变的值不变

Page 20: Lua Programming Skills and Optimizations

多行字符串多行字符串local str = [[local str = [[

hihi

kimkim

]]]]

类似 类似 PHP PHP 的 的 heredocheredoc

Page 21: Lua Programming Skills and Optimizations

模式匹配符模式匹配符Lua Lua 模式匹配使用 模式匹配使用 % % 来转义,而不是来转义,而不是““ \”\”

string.find(str,”%.”) -- string.find(str,”%.”) -- 寻找逗号位置寻找逗号位置

Page 22: Lua Programming Skills and Optimizations

数组下标数组下标TableTable 的数字下标从的数字下标从 11 开始,而不是开始,而不是 00

table = {10, a = 20, 30}table = {10, a = 20, 30}

print(table[1]) -- 10print(table[1]) -- 10

print(table[2]) -- 30print(table[2]) -- 30

Page 23: Lua Programming Skills and Optimizations

二维数组二维数组mt = {}mt = {}

for i = 1, N dofor i = 1, N do

mt[i] = {} -- mt[i] = {} -- 注意要先定义注意要先定义 for j = 1, M dofor j = 1, M do

mt[i][j] = i * jmt[i][j] = i * j

endend

endend

Page 24: Lua Programming Skills and Optimizations

复制复制 TableTable

Lua Lua 的 的 table table 复制都是引用赋值复制都是引用赋值即新增一个对 即新增一个对 table table 的引用的引用

local a = {}local a = {}

local b = a -- a local b = a -- a 和 和 b b 都引用同一个 都引用同一个 tabletable

Page 25: Lua Programming Skills and Optimizations

比较 比较 TableTable

Lua Lua 通过“引用”对 通过“引用”对 tabletable 、、 userdata userdata 和 函和 函数 等进行比较,只有当他们引用同一个对象时,数 等进行比较,只有当他们引用同一个对象时,才视为相等。才视为相等。

local a, b = {1}, {1}local a, b = {1}, {1}

a == b -- falsea == b -- false

Page 26: Lua Programming Skills and Optimizations

稀疏矩阵稀疏矩阵Table Table 天生就是稀疏矩阵天生就是稀疏矩阵

Page 27: Lua Programming Skills and Optimizations

函数的意义函数的意义函数 函数 print print ::

持有“打印字符串功能”这个函数的名为 持有“打印字符串功能”这个函数的名为 print print

的变量的变量

Page 28: Lua Programming Skills and Optimizations

函数函数 vsvs 方法方法调用 调用 obj obj 模块下的函数:模块下的函数:

11 )) obj.foo(obj, x)obj.foo(obj, x)

22 )) obj:foo(x) -- obj:foo(x) -- 转换成方法调用,实际上是把 转换成方法调用,实际上是把 obj obj 隐式的作为第一个参数隐式的作为第一个参数

Page 29: Lua Programming Skills and Optimizations

函数调用函数调用建议统一使用 建议统一使用 () () 来调用函数:来调用函数: print “hello world” -- print “hello world” -- 不建议不建议print("hello world") -- print("hello world") -- 建议建议

Page 30: Lua Programming Skills and Optimizations

模块定义模块定义module(...) module(...) 相当于做了以下的事情:相当于做了以下的事情:

local modname = ... -- local modname = ... -- 当前模块名当前模块名local M = {} -- local M = {} -- 定义模块定义模块_G[modname] = M -- _G[modname] = M -- 把模块加到全局变量中把模块加到全局变量中package.loaded[modname] = M -- package.loaded[modname] = M -- 模块已加载成功模块已加载成功setmetatable(M, {__index = _G}) -- setmetatable(M, {__index = _G}) -- 模块可以直接访模块可以直接访

问所有全局变量,相当于 问所有全局变量,相当于 module(..., module(..., package.seeall)package.seeall)

setfenv(1, M) -- setfenv(1, M) -- 保证在模块内定义和调用的函数都以模保证在模块内定义和调用的函数都以模块名为前缀块名为前缀

Page 31: Lua Programming Skills and Optimizations

模块加载模块加载模块加载(模块加载( requirerequire )原理:)原理: function require(name)function require(name)

if not package.loaded[name] thenif not package.loaded[name] then

local loader = findloader(name)local loader = findloader(name)

if loader == nil thenif loader == nil then

error("unable to load module " .. name)error("unable to load module " .. name)

endend

package.load[name] = truepackage.load[name] = true

local res = loader(name)local res = loader(name)

if res ~= nil thenif res ~= nil then

package.loaded[name] = respackage.loaded[name] = res

endend

endend

return package.loaded[name]return package.loaded[name]

endend

Page 32: Lua Programming Skills and Optimizations

访问模块外的变量访问模块外的变量11 )) setmetatable(M, {__index = _G}) -- setmetatable(M, {__index = _G}) -- 模块可直接访问全局变模块可直接访问全局变

量量

22 )) local _G = _G -- local _G = _G -- 可通过 可通过 _G.abc _G.abc 的方式来调用全局的 的方式来调用全局的 abc abc 变变量量

33 )按需加载,例如:)按需加载,例如: local math = math -- local math = math -- 在模块顶部显示的调用在模块顶部显示的调用 (如果是使用 (如果是使用 lua5.1 lua5.1 的 的 module module 函数来创建模块的话函数来创建模块的话 就只能通过这种方式来提供外部访问。)就只能通过这种方式来提供外部访问。)

Page 33: Lua Programming Skills and Optimizations

Lua Lua 性能优化性能优化

Page 34: Lua Programming Skills and Optimizations

尽量使用 尽量使用 localslocals

for i = 1, 1000000 dofor i = 1, 1000000 do

local x = math.sin(i)local x = math.sin(i)

endend

-- -- 下面这个快下面这个快 30%30% 左右左右 ::

local sin = math.sinlocal sin = math.sin

for i = 1, 1000000 dofor i = 1, 1000000 do

local x = sin(i)local x = sin(i)

endend

Page 35: Lua Programming Skills and Optimizations

Loadstring Loadstring 和 和 ClosureClosure

尽量不用 尽量不用 loadstring loadstring ,用 ,用 closure closure 来代替,执行时间减少到 来代替,执行时间减少到 1/101/10

当然 当然 closure closure 闭包能不用就不用闭包能不用就不用

Page 36: Lua Programming Skills and Optimizations

数字索引 数字索引 tabletable

lua lua 的 的 table table 由数字索引和字符串索引两部分组成。由数字索引和字符串索引两部分组成。

尽量使用数字索引 尽量使用数字索引 arrayarray ,而不使用 ,而不使用 hash tablehash table ::1. 1. 较大幅度提升性能较大幅度提升性能2. 2. 能减少内存使用能减少内存使用

Page 37: Lua Programming Skills and Optimizations

提前 提前 hashhash为 为 table table 预先留位,可以省去 预先留位,可以省去 rehash rehash 的消耗的消耗

for i = 1, 1000000 dofor i = 1, 1000000 do

local a = {}local a = {}

a[1] = 1; a[2] = 2; a[3] = 3a[1] = 1; a[2] = 2; a[3] = 3

endend

-- -- 下面的快了下面的快了 60%60%

for i = 1, 1000000 dofor i = 1, 1000000 do

local a = {true, true, true}local a = {true, true, true}

a[1] = 1; a[2] = 2; a[3] = 3a[1] = 1; a[2] = 2; a[3] = 3

endend

Page 38: Lua Programming Skills and Optimizations

慎用正则慎用正则

Lua Lua 没有 没有 POSIX POSIX 和 和 PCREPCRE ,这正是告诉我们一个明确的信号:,这正是告诉我们一个明确的信号:尽量不要使用正则表达式!尽量不要使用正则表达式!

Page 39: Lua Programming Skills and Optimizations

字符串缓冲字符串缓冲字符串连接可以使用 字符串连接可以使用 table table 作为缓冲,然后用 作为缓冲,然后用 concat concat 来连接来连接

local s = '';local s = '';

for line in io.lines() dofor line in io.lines() do

s = s .. line .. “\n” -- s = s .. line .. “\n” -- 创建一个新字符串 创建一个新字符串 ss ,内存移动 ,内存移动 s s 这么大这么大endend

-- -- 下面这个要快十倍,特别是大文件下面这个要快十倍,特别是大文件local t = {}local t = {}

for line in io.lines() dofor line in io.lines() do

t[#t + 1] = linet[#t + 1] = line

endend

t[#t + 1] = ''t[#t + 1] = ''

s = table.concat(t, "\n")s = table.concat(t, "\n")

Page 40: Lua Programming Skills and Optimizations

高效输出高效输出

print(a, b, c) print(a, b, c) 比 比 print(a..b..c) print(a..b..c) 更高效更高效io.write(a, b, c) io.write(a, b, c) 比 比 io.write(a..b..c) io.write(a..b..c) 更高效更高效

lua lua 还有很多这样的例子,原则是尽量避免创建字符串中间变量还有很多这样的例子,原则是尽量避免创建字符串中间变量

Page 41: Lua Programming Skills and Optimizations

一次性定义一次性定义-- -- 定义一个对象并初始化定义一个对象并初始化a = {}; a.x = 10; a.y = 20a = {}; a.x = 10; a.y = 20

-- -- 用一次性定义,快用一次性定义,快 60%60%

a = { x = 10, y = 20 }a = { x = 10, y = 20 }

Page 42: Lua Programming Skills and Optimizations

Table Table 重用重用local t = {}local t = {}

for i = 1970, 2000 dofor i = 1970, 2000 do

t[i] = os.time({year = i, month = 6, day = 14})t[i] = os.time({year = i, month = 6, day = 14})

endend

-- -- 下面的快下面的快 50%50% ,内存也使用更少,内存也使用更少local t = {}local t = {}

local aux = {year = nil, month = 6, day = 14}local aux = {year = nil, month = 6, day = 14}

for i = 1970, 2000 dofor i = 1970, 2000 do

aux.year = iaux.year = i

t[i] = os.time(aux)t[i] = os.time(aux)

endend

Page 43: Lua Programming Skills and Optimizations

慎用回收慎用回收

不要随便调用 不要随便调用 collectgarbagecollectgarbage

因为它不一定有助于改善性能,要看实际情况而定因为它不一定有助于改善性能,要看实际情况而定

Page 44: Lua Programming Skills and Optimizations

慎用变长参数慎用变长参数

除非是公开、不变的协议,否则函数除非是公开、不变的协议,否则函数 //方法中尽量不使用变长参数 方法中尽量不使用变长参数 ......

1. 1. 不容易理解不容易理解2. 2. 容易出容易出 bugbug

3. 3. 不容易移植不容易移植

Page 45: Lua Programming Skills and Optimizations

低效的低效的 dofiledofile

-- -- 通过 通过 dofile dofile 或者或者 loadfile loadfile 加载解析的 加载解析的 lua lua 文件是不会被缓存的文件是不会被缓存的function dofile(filename)function dofile(filename)

local f = assert(loadfile(filename)) -- file io, no cachelocal f = assert(loadfile(filename)) -- file io, no cache

return f()return f()

endend

Page 46: Lua Programming Skills and Optimizations

LUA_PATHLUA_PATH

尽量把经常用到的模块,或者自定义模块路径放到尽量把经常用到的模块,或者自定义模块路径放到package.pathpackage.path (( LUA_PATHLUA_PATH ) 最前面,比如:) 最前面,比如:

lua_package_path “./?.lua;/mylib/?.lua;lua_package_path “./?.lua;/mylib/?.lua;

/home/openresty/lualib/?.lua;/otherlib/?.lua;?.lua/home/openresty/lualib/?.lua;/otherlib/?.lua;?.lua

;;”;;”

Page 47: Lua Programming Skills and Optimizations

全局扫描全局扫描

尽量不要在调用 尽量不要在调用 module module 时使用 时使用 package.seeall package.seeall 参数参数因为这会导致全局扫描和跨环境调用因为这会导致全局扫描和跨环境调用

Page 48: Lua Programming Skills and Optimizations

全局扫描全局扫描

尽量不要在调用 尽量不要在调用 module module 时使用 时使用 package.seeall package.seeall 参数参数因为这会导致全局扫描和跨环境调用因为这会导致全局扫描和跨环境调用

Page 49: Lua Programming Skills and Optimizations

Debug Debug 库库

线上环境尽量不要使用 线上环境尽量不要使用 debug debug 库,必要时 库,必要时 debug = nil debug = nil 清理掉清理掉

Page 50: Lua Programming Skills and Optimizations

解析器解析器

LuaJIT LuaJIT 是目前为止最快的解析器,非必要情况不要更换。是目前为止最快的解析器,非必要情况不要更换。

Page 51: Lua Programming Skills and Optimizations

FAQFAQ

Page 52: Lua Programming Skills and Optimizations

谢谢!谢谢!