zoukankan      html  css  js  c++  java
  • 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,"
    ")
      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,"
    ")
      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("
    ")
    end
    
  • 相关阅读:
    uva11922splay
    获取的二维数组排序
    二维数组排序
    $.extend
    <eq>标签
    datagrid时间插件
    id=%d是什么意思呢?
    获得某一月的第一天,最后一天
    数组合并
    phpexcel 导入导出excel表格
  • 原文地址:https://www.cnblogs.com/tangyikejun/p/luacoroutine.html
Copyright © 2011-2022 走看看