协同程序
Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。
协同是非常强大的功能,但是用起来也很复杂。
线程和协同程序区别
线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。
在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。
协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。
coroutine.create() | 创建 coroutine,返回 coroutine, 参数是一个函数,当和 resume 配合使用的时候就唤醒函数调用 |
coroutine.resume() | 重启 coroutine,和 create 配合使用 |
coroutine.yield() | 挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果 |
coroutine.status() | 查看 coroutine 的状态 注:coroutine 的状态有三种:dead,suspended,running,具体什么时候有这样的状态请参考下面的程序 |
coroutine.wrap() | 创建 coroutine,返回一个函数,一旦你调用这个函数,就进入 coroutine,和 create 功能重复 |
coroutine.running() | 返回正在跑的 coroutine,一个 coroutine 就是一个线程,当使用running的时候,就是返回一个 corouting 的线程号 |
print("==========协成的创建===========");
fun=function()
print("一个create协成");
end
fun1=function()
print("一个wrap协成");
end
--这里创建的协成本质是一个线程
co=coroutine.create(fun);
print(type(co))
--这里是一个函数
co2=coroutine.wrap(fun1)
print(type(co2))
print("==========协成的运行===========");
coroutine.resume(co);
co2();
print("==========协成的挂起===========");
fun2=function ()
local i=1
while true do
print(i)
i=i+1
--协成挂起
--第一个返回值是判断是否执行成功,第二个是具体的返回值
coroutine.yield(i)
end
end
co3=coroutine.create(fun2)
isok, temp= coroutine.resume(co3)
print(isok,temp)
isok, temp= coroutine.resume(co3)
print(isok,temp)
print("==========协成的状态===========");
print( coroutine.status(co3))
元表
在 Lua table 中我们可以访问对应的 key 来得到 value 值,但是却无法对两个 table 进行操作(比如相加)。
因此 Lua 提供了元表(Metatable),允许我们改变 table 的行为,每个行为关联了对应的元方法。
例如,使用元表我们可以定义 Lua 如何计算两个 table 的相加操作 a+b。
当 Lua 试图对两个表进行相加时,先检查两者之一是否有元表,之后检查是否有一个叫 __add 的字段,若找到,则调用对应的值。 __add 等即时字段,其对应的值(往往是一个函数或是 table)就是"元方法"。
__index 元方法
这是 metatable 最常用的键。
当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。如果__index包含一个表格,Lua会在表格中查找相应的键。
--[[
__index 当子表中找不到某一个属性时,会到元表中__index指定的表中去找索引
]]
meta6={
-- age=6
-- __index={age=6}最好写在外边
}
meta6.__index={age=6}
mytable6={}
setmetatable(mytable6, meta6)
print(mytable6.age)
__newIndex 元方法
__newindex 元方法用来对表更新,__index则用来对表访问 。
当你给表的一个缺少的索引赋值,解释器就会查找__newindex 元方法:如果存在则调用这个函数而不进行赋值操作。
--[[
newIndex 当赋值时,如果赋值一个不存在的索引
那么会把这个值赋值到newIndes所指的表中,不会修改自己
]]
meta7={}
meta7.__newIndex={}
mytable7={}
setmetatable(mytable7, meta7)
mytable7.age=8
print(mytable7.age)
__call 元方法
__call 元方法在 Lua 调用一个值时调用。以下实例演示了计算表中元素的和:
meta3={
--当”子表“要被当字符串使用的时候,会默认调用元表中的tostring方法
__tostring=function (t)
return t.name
end,
--但子表被当作一个函数使用的时候,默认调用call
__call=function ()
print("李四")
end
}
mytable3={
name="张三"
}
setmetatable(mytable3,meta3)
print(mytable3)
mytable3();
__tostring 元方法
__tostring 元方法用于修改表的输出行为。以下实例我们自定义了表的输出内容:
meta2={
--当”子表“要被当字符串使用的时候,会默认调用元表中的tostring方法
__tostring=function (t)
return t.name
end
}
mytable2={
name="张三"
}
setmetatable(mytable2,meta2)
print(mytable2)
为表添加操作符
模式 | 描述 |
---|---|
__add | 对应的运算符 '+'. |
__sub | 对应的运算符 '-'. |
__mul | 对应的运算符 '*'. |
__div | 对应的运算符 '/'. |
__mod | 对应的运算符 '%'. |
__unm | 对应的运算符 '-'. |
__concat | 对应的运算符 '..'. |
__eq | 对应的运算符 '=='. |
__lt | 对应的运算符 '<'. |
__le | 对应的运算符 '<='. |
meta4={
--表之间的加法
__add=function (t1,t2)
return t1.age+t2.age
end
--[[
__add 对应的运算符 '+'.
__sub 对应的运算符 '-'.
__mul 对应的运算符 '*'.
__div 对应的运算符 '/'.
__mod 对应的运算符 '%'.
__unm 对应的运算符 '-'.
__concat 对应的运算符 '..'.
__eq 对应的运算符 '=='.
__lt 对应的运算符 '<'.
__le 对应的运算符 '<='.
]]
}
mytable4={
age=1;
}
setmetatable(mytable4, meta4)
mytable5={
age=5;
}
print(mytable4+mytable5)