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

同时发布于博客园:http://www.cnblogs.com/tangyi...


tangyikejun
259 声望36 粉丝