学习资料
阅读笔记,只是记录了知识点和一些注意点,详细的看上面提供的学习资料链接
-
Lua 基础数据类型
- nil(空)
- boolean(布尔)
- Lua 中 nil 和 false 为“假”,其它所有值均为“真”
- number(数字)
- string(字符串)
- 使用一对匹配的单引号。例:'hello'。
- 使用一对匹配的双引号。例:"abclua"。
- 字符串还可以用一种长括号(即[[ ]])括起来的方式定义
- Lua 字符串一般都会经历一个“内化”(intern)的过程,即两个完全一样的 Lua 字符串在 Lua 虚拟机中只会存储一份
- table (表)
- function (函数)
-
表达式
-
控制结构
- if-else
- else 与 if 是连在一起的,若将 else 与 if 写成 "else if" 则相当于在 else 里嵌套另一个 if 语句
- while
- repeat
- 执行 repeat 循环体后,直到 until 的条件为真时才结束
- for
- Lua 标准库提供了几种迭代器,包括用于迭代文件中每行的(io.lines)、 迭代 table 元素的(pairs)、迭代数组元素的(ipairs)、迭代字符串中单词的(string.gmatch)
- 最好使用ipairs,ipairs() 内建函数是可以被 JIT 编译的
- break,return 和 goto
- return 若要写在函数中间,则只能写在一个显式的语句块内 或者 直接写成do return end,否则会报错
- 提供 goto 代替 continue
-
Lua函数
- 使用local修饰符标记局部函数
- 变长参数使用"..."(三个点),若对性能敏感的代码,应当避免使用此种形式
- 函数的返回值允许函数返回多个值,返回多个值时,值之间用","隔开
- 全动态函数调用
local args = {...} or {}
method_name(unpack(args, 1, table.maxn(args)))
- 点号与冒号操作符的区别
- 冒号操作会带入一个 self 参数,用来代表 自己,冒号的操作,只有当变量是类对象时才需要
- 点号操作,只是 内容 的展开
local str = "abcde"
print("case 1:", str:sub(1, 2))
print("case 2:", str.sub(str, 1, 2))
-
模块
-
String库
- Lua 字符串内部用来标识各个组成字节的下标是从 1 开始的
- string.byte(s [, i [, j ]])
- string.char (...)
- string.upper(s)
- string.lower(s)
- string.len(s)
- 使用此函数是不推荐的。应当总是使用 # 运算符来获取 Lua 字符串的长度。
- string.find(s, p [, init [, plain]])
- string.format(formatstring, ...)
- string.match(s, p [, init])
- 目前并不能被 JIT 编译,应 尽量 使用 ngx_lua 模块提供的 ngx.re.match 等接口
- string.gmatch(s, p)
- 目前并不能被 LuaJIT 所 JIT 编译,而只能被解释执行。应 尽量 使用 ngx_lua 模块提供的 ngx.re.gmatch 等接口。
- string.rep(s, n)
- string.sub(s, i [, j])
- string.gsub(s, p, r [, n])
- 此函数不能为 LuaJIT 所 JIT 编译,而只能被解释执行。一般我们推荐使用 ngx_lua 模块提供的 ngx.re.gsub 函数。
- string.reverse (s)
-
table库
- 下标从 1 开始
- 取长度操作符写作一元操作 #
- 判断数组大小
- table.getn(t) 计算的是数组元素,不包括 hash 键值,以第一个 nil 元素来判断数组结束
- # 只计算 array 的元素个数,实际上调用了对象的 metatable 的 __len 函数
- 一定不要使用 # 操作符或 table.getn 来计算包含 nil 的数组长度
- 不要在 Lua 的 table 中使用 nil 值,如果一个元素要删除,直接 remove,不要用 nil 去代替
- table.getn 获取长度
- 对于有“空洞nil值”的情况,table 的长度存在一定的 不可确定性。
- table.concat (table [, sep [, i [, j ] ] ])
- table.insert (table, [pos ,] value)
- table.maxn (table)
- table.remove (table [, pos])
- table.sort (table [, comp])
- table.new 预分配 Lua table 空间
- table.clear 释放 table 空间
-
日期时间函数
推荐使用 ngx_lua 模块提供的带缓存的时间接口,如 ngx.today, ngx.time, ngx.utctime, ngx.localtime, ngx.now, ngx.http_time,以及 ngx.cookie_time 等
- os.time ([table])
- os.difftime (t2, t1)
- os.date ([format [, time]])
-
数学库
- math.rad(x) 角度x转换成弧度
- math.deg(x) 弧度x转换成角度
- math.max(x, ...) 返回参数中值最大的那个数,参数必须是number型
- math.min(x, ...) 返回参数中值最小的那个数,参数必须是number型
- math.random ([m [, n]]) 不传入参数时,返回 一个在区间[0,1)内均匀分布的伪随机实数;只使用一个整数参数m时,返回一个在区间[1, m]内均匀分布的伪随机整数;使用两个整数参数时,返回一个在区间[m, n]内均匀分布的伪随机整数
- math.randomseed (x) 为伪随机数生成器设置一个种子x,相同的种子将会生成相同的数字序列
- math.abs(x) 返回x的绝对值
- math.fmod(x, y) 返回 x对y取余数
- math.pow(x, y) 返回x的y次方
- math.sqrt(x) 返回x的算术平方根
- math.exp(x) 返回自然数e的x次方
- math.log(x) 返回x的自然对数
- math.log10(x) 返回以10为底,x的对数
- math.floor(x) 返回最大且不大于x的整数
- math.ceil(x) 返回最小且不小于x的整数
- math.pi 圆周率
- math.sin(x) 求弧度x的正弦值
- math.cos(x) 求弧度x的余弦值
- math.tan(x) 求弧度x的正切值
- math.asin(x) 求x的反正弦值
- math.acos(x) 求x的反余弦值
- math.atan(x) 求x的反正切值
-
文件操作
实际中的应用,在 OpenResty 项目中应尽可能让网络处理部分、文件 I/0 操作部分相互独立,不要揉和在一起
- io.open (filename [, mode])
- file:close ()
- io.close ([file])
- file:flush ()
- io.flush ()
- io.input ([file])
- file:lines ()
- io.lines ([filename])
- io.output ([file])
- file:read (...)
- io.read (...)
- io.type (obj)
- file:write (...)
- io.write (...)
- file:seek ([whence] [, offset])
- file:setvbuf (mode [, size])
-
元表
- 元表 (metatable) 的表现行为类似于 C++ 语言中的操作符重载
- 两个十分重要的用来处理元表的方法
- setmetatable(table, metatable):此方法用于为一个表设置元表。
- getmetatable(table):此方法用于获取表的元表对象。
- 可被重载的元方法
元方法 |
含义 |
__add |
+ 操作 |
__sub |
- 操作 其行为类似于 "add" 操作 |
__mul |
* 操作 其行为类似于 "add" 操作 |
__div |
/ 操作 其行为类似于 "add" 操作 |
__mod |
% 操作 其行为类似于 "add" 操作 |
__pow |
^ (幂)操作 其行为类似于 "add" 操作 |
__unm |
一元 - 操作 |
__concat |
.. (字符串连接)操作 |
__len |
# 操作 |
__eq |
== 操作 函数 getcomphandler 定义了 Lua 怎样选择一个处理器来作比较操作 仅在两个对象类型相同且有对应操作相同的元方法时才起效 |
__lt |
< 操作 |
__le |
<= 操作 |
__index |
取下标操作用于访问 table[key] |
__newindex |
赋值给指定下标 table[key] = value |
__tostring |
转换成字符串 |
__call |
当 Lua 调用一个值时调用 |
__mode |
用于弱表(week table) |
__metatable |
用于保护metatable不被访问 |
-
Lua 面向对象编程
-
FFI
-
FFI 库,是 LuaJIT 中最重要的一个扩展库
-
词库解释
名词 |
解释 |
cdecl |
A definition of an abstract C type(actually, is a lua string) |
ctype |
C type object |
cdata |
C data object |
ct |
C type format, is a template object, may be cdecl, cdata, ctype |
cb |
callback object |
VLA |
An array of variable length |
VLS |
A structure of variable length |
-
在 lua 文件中使用 ffi 库的时候,必须要有这一行:local ffi = require "ffi"
-
ffi.cdef
- 语法:ffi.cdef(def)
- 功能:声明 C 函数或者 C 的数据结构
-
ffi.typeof
- 语法:ffi.cdef(def)
- 功能:创建一个 ctype 对象,会解析一个抽象的 C 类型定义
-
ffi.new
- 语法:cdata = ffi.new(ct [,nelem] [,init...])
- 功能:开辟空间,第一个参数为 ctype 对象,ctype 对象最好通过 ctype = ffi.typeof(ct) 构建
-
ffi.fill
- 语法:ffi.fill(dst, len [,c])
- 功能:填充数据
-
ffi.cast
- 语法:cdata = ffi.cast(ct, init)
- 功能:创建一个 scalar cdata 对象。
-
调用 C 函数
- 加载 FFI 库。
- 为函数增加一个函数声明。这个包含在 中括号 对之间的部分,是标准 C 语法。
- 调用命名的 C 函数
local ffi = require("ffi")
ffi.cdef[[
int printf(const char *fmt, ...);
]]
ffi.C.printf("Hello %s!", "world")
-
防止内存泄漏的方案
- 在调用 resource = ffi.C.xx_create 等申请资源的函数之后,立即补上一行 ffi.gc(resource, ...) 来注册释放资源的函数
- 有些时候,ffi.C.xx_create 返回的不是具体的 cdata,而是整型的 handle。这会儿需要用 ffi.metatype 把 ffi.gc 包装一下
local resource_type = ffi.metatype("struct {int handle;}", {
__gc = free_resource
})
local function free_resource(handle)
...
end
resource = ffi.new(resource_type)
resource.handle = ffi.C.xx_create()
-
JIT
可以通过 ngx-lj-gc-objs 工具看到指定的 Nginx worker 进程里所有 trace 对象的一些基本的统计信息:https://github.com/openresty/stapxx#ngx-lj-gc-objs
我们如何才能知道具体是哪一行 Lua 代码上的哪一个 NYI 原语终止了 trace 编译呢?
答案很简单。就是使用 LuaJIT 安装自带的 jit.v 和 jit.dump 这两个 Lua 模块。这两个 Lua 模块会打印出 JIT 编译器工作的细节过程
完整的 NYI 列表:http://wiki.luajit.org/NYI
可以使用 ab 和 weighttp 这样的工具对相应的服务接口进行预热,以触发 LuaJIT 的 JIT 编译器开始工作
|
请发表评论