Lua 协程
lua 协程
简介
从本菜的认知角度看,协程就是一个函数可以一段一段分开来执行,功能和时间序列聚合,执行分离。
相关的三个函数
1. coroutine.create(cofun)
参数
-cofun 等待执行的协同函数
返回值
该协同程序的实例对象,该对象是一个 thread 类型的值
2. ret,... = coroutine.resume(co[,...])
参数
-co 需要恢复的协同程序实例对象
-... 需要传递给协同程序的参数,也就是协同函数的实参
返回值
-ret 函数执行成功返回 true,执行失败返回 false
-... 接收传入 yield 的实参
说明
resume 函数在保护模式下运行,如果协同程序运行过程中发生了错误,lua并不会显示错误消息,而是直接从 resume 返回,此时返回的第一个参数为 false
3. ... = coroutine.yield(...)
参数
-... 传入的参数将会由 resume 函数返回
返回值
-... resume 函数传入什么,这里就返回什么
说明
yield 不能使用在元方法内部或者 pcall 内部
4. status = coroutine.status(co)
参数
-co 传入需要查看状态的协程实例对象,该参数不可省略哟
返回值
-status 一共running,suspended,normal,dead 四种状态
说明
normal 状态是指这样一个协程,它当前正作为调用者执行另外一个协同程序。
简单示例
1. 简单协程对象的创建、使用与状态查看
local co = coroutine.create(function () -- 创建一个协同程序对象 co
print("Im in the coroutine~haha")
coroutine.yield() -- 第一次执行到此处挂起
print("Im in the coroutine again !!")
end)
coroutine.resume(co) -- 第一次恢复协同程序 co
print(coroutine.status(co)) -- 查看当前协同程序的状态,发现协同程序已经被挂起
coroutine.resume(co) -- 第二次执行协同程序
print(coroutine.status(co)) -- 查看当前协同程序的状态,发现协同程序已经死亡
-- output>> Im in the coroutine~haha
-- output>> suspended
-- output>> Im in the coroutine again !!
-- output>> dead
2. 协程中的参数传递
--根据字符串长度生成一个口令
local co = coroutine.create(function (basekey)
while(1)do
local salt = io.read()
print("basekey:",basekey)
local key1 = (basekey * #salt)..salt
local yret = coroutine.yield(1,key1)
print("yield return1:",yret)
local key2 = salt..(basekey * #salt)
yret = coroutine.yield(2,key2)
print("yield return2:",yret)
end
end)
math.randomseed(os.time())
while(1) do
local rand = math.random(1,100)
print("rand:",rand)
local ret,selNo,key = coroutine.resume(co,rand)
if ret then
print(string.format("The %d key is %s",selNo,key))
else
print("generate fail")
break
end
end
-- output>> rand: 21
-- input >> good
-- output>> basekey: 21
-- output>> The 1 key is 84good
-- output>> rand: 79
-- output>> yield return1: 79
-- output>> The 2 key is good84
-- output>> rand: 66
-- output>> yield return2: 66
-- input >> job
-- output>> basekey: 21
-- output>> The 1 key is 63job
-- output>> rand: 78
-- output>> yield return1: 78
-- output>> The 2 key is job63
-- output>> rand: 83
-- output>> yield return2: 83
-- input >> tangyikejun
-- output>> basekey: 21
-- output>> The 1 key is 231tangyikejun
-- output>> rand: 10
-- output>> yield return1: 10
-- output>> The 2 key is tangyikejun231
-- output>> rand: 68
-- output>> yield return2: 68
上面的输出值得注意的是,basekey 的值一直都是 21 ,尽管rand 得到的随机数一直都在变。而 yield 的返回值则是下一次resume时传入的参数。
以上代码仅仅演示用法,可能并无任何实际意义。
生产者与消费者
本例源自 《 Lua 程序设计第二版》
-- 生产者 作为协程
producer = coroutine.create(function()
while true do
local x = io.read()
send(x)
end
end
)
-- 消费者
function consumer()
while true do
local x = receive()
io.write(x,"\n")
end
end
-- 向生产者发起请求获取信息
function receive()
local status,value = coroutine.resume(producer)
return value
end
-- 生产者将信息返回给消费者
function send(x)
coroutine.yield(x) -- 发送数据 x 给协程调用者
end
-- 消费者驱动
consumer()
过滤器参与的生产者与消费者
本例源自 《 Lua 程序设计第二版》
有点类似于 linux 的 pipe 管道
function receive(producer)
local status,value = coroutine.resume(producer)
return value
end
function send(x)
coroutine.yield(x) -- 发送数据 x 给协程调用者
end
-- 生产者 作为协程
function producer()
return coroutine.create(function()
while true do
local x = io.read()
send(x)
end
end
)
end
function filter(producer)
return coroutine.create(function ()
for line = 1,math.huge do
local x = receive(producer)
x = string.format("%5d %s",line,x)
send(x)
end
end)
end
-- 消费者
function consumer(producer)
while true do
local x = receive(producer)
io.write(x,"\n")
end
end
local p = producer()
local f = filter(p)
consumer(f)
基于协程的迭代器
本例源自 《 Lua 程序设计第二版》
-- 一个逐一获得全排列的迭代器
-- 生成全排列
function mygen(a,n)
if n == 1 then
coroutine.yield(a)
end
for i=1,n do
a[n],a[i] = a[i],a[n]
mygen(a,n-1)
a[n],a[i] = a[i],a[n]
end
end
-- 迭代器
function permutation(a)
local co = coroutine.create(mygen)
return function ()
local res,t = coroutine.resume(co,a,#a,"")
return t
end
end
-- 使用
for a in permutation({1,2,3,4}) do
for i,v in ipairs(a) do
io.write(v)
end
io.write("\n")
end