Lua中协程都放在表coroutine中。

Lua协程的四个状态

  1. 挂起(suspended):一个协程被创建的时候,处于挂起状态,不会自动运行。
  2. 运行(running):coroutine.resume()用于启动或者再次启动一个协程,使其变成运行状态。
  3. 正常(normal):协程A唤醒协程B的时候,协程B处于运行状态,协程A就处于正常状态。
  4. 死亡(dead):协程中包含的函数执行完毕,协程就变成了死亡状态。

Lua协程的操作函数:

创建协程:coroutine.create(func)

该函数接受一个函数作为参数,返回一个thread类型的值。

例如:

  1. local co = coroutine.create(function() print("hello") end)
  2. print(type(co))

输出:

  1. thread

启动协程:coroutine.resume(co, arg1, arg2, ...)

参数:可以分为两种情况。

1.协程中不包含yield():第一个参数是被启动的协程,后面的参数传递给协程封装的函数作为参数。

例如:

  1. local co = coroutine.create(
  2. function(a, b)
  3. print("a + b =", a + b)
  4. end
  5. )
  6. coroutine.resume(co, 1, 2)

输出:

  1. a + b = 3

2.协程中包含yield():第一个参数还是被启动的线程,在首次调用resume时,后面的参数传递给协程封装的函数作为参数;而再次调用(非首次)resume()时,后面的参数将作为yield()的返回值。

例如:

  1. local co = coroutine.create(
  2. function(x)
  3. print("co1", x)
  4. print("co2", coroutine.yield())
  5. end
  6. )
  7. coroutine.resume(co, "hello")
  8. coroutine.resume(co, "world")

输出:

  1. co1 hello
  2. co2 world

返回值:分为三种情况。

1.协程没有结束,resume()第一个返回值是true,后面的返回值是yield(...)中的参数。

2.协程结束时,resume()第一个返回值是true,后面的返回值是协程中函数的返回值。

3.协程结束后,此时不应该继续调用resume,如果调用了,resume()第一个返回值是false,表示调用失败,第二个返回值是报错信息。

例如:

  1. local co = coroutine.create(
  2. function()
  3. coroutine.yield("hello", "world")
  4. return "hello", "lua"
  5. end
  6. )
  7. print(coroutine.resume(co))
  8. print(coroutine.resume(co))
  9. print(coroutine.resume(co))

输出:

  1. true hello world
  2. true hello lua
  3. false cannot resume dead coroutine

值得注意的是,resume运行在保护模式中,如果协程在执行过程中遇到了错误,Lua不会打印错误信息,而是把错误信息作为resume()的返回值。

挂起协程:coroutine.yield(arg1, arg2, ...)

参数:yield()将作为本次唤醒协程的resume()的返回值。

返回值:下次唤醒协程的resume()的参数,将作为yield()的返回值。

例如:

  1. local co = coroutine.create(
  2. function()
  3. local ret = coroutine.yield("hello")
  4. print(ret)
  5. end
  6. )
  7. local state, ret = coroutine.resume(co)
  8. print(state)
  9. print(ret)
  10. coroutine.resume(co, "world")

输出:

  1. true
  2. hello
  3. world

Lua协程的特点

Lua协程是一种非对称协程(asymmetric coroutine),需要两个函数来控制协程的执行,一个用于挂起协程,一个用于恢复协程。

相对于其他语言提供的对称协程(symmetric coroutine),只提供一个函数用于切换不同协程之间的控制权。

Lua协程的一些应用

1.生产者消费者问题:

1.消费者驱动型

  1. -- 消费者驱动型 consumer-driven
  2. producer_co = coroutine.create(
  3. function()
  4. for i = 1, 5 do
  5. print("produce:", i)
  6. coroutine.yield(i)
  7. end
  8. end
  9. )
  10. function consumer()
  11. while true do
  12. local status, value = coroutine.resume(producer_co)
  13. print("producer:", coroutine.status(producer_co))
  14. if not value then
  15. break
  16. end
  17. print("consume:", value)
  18. end
  19. end
  20. consumer()

输出:

  1. produce: 1
  2. producer: suspended
  3. consume: 1
  4. produce: 2
  5. producer: suspended
  6. consume: 2
  7. produce: 3
  8. producer: suspended
  9. consume: 3
  10. produce: 4
  11. producer: suspended
  12. consume: 4
  13. produce: 5
  14. producer: suspended
  15. consume: 5
  16. producer: dead

2.生产者驱动型

  1. -- 生产者驱动型 producer-driven
  2. function producer()
  3. for i = 1, 5 do
  4. print("produce:", i)
  5. coroutine.resume(consumer_co, i)
  6. print("consumer:", coroutine.status(consumer_co))
  7. end
  8. coroutine.resume(consumer_co)
  9. end
  10. consumer_co = coroutine.create(
  11. function(x)
  12. while true do
  13. print("consume:", x)
  14. x = coroutine.yield()
  15. if not x then
  16. break
  17. end
  18. end
  19. end
  20. )
  21. producer()
  22. print("consumer:", coroutine.status(consumer_co))

输出:

  1. produce: 1
  2. consume: 1
  3. consumer: suspended
  4. produce: 2
  5. consume: 2
  6. consumer: suspended
  7. produce: 3
  8. consume: 3
  9. consumer: suspended
  10. produce: 4
  11. consume: 4
  12. consumer: suspended
  13. produce: 5
  14. consume: 5
  15. consumer: suspended
  16. consumer: dead

2.将协程用作迭代器:

  1. -- 产生全排列的迭代器
  2. function permutation_gen(a, n)
  3. n = n or #a
  4. if n < 1 then
  5. coroutine.yield(a)
  6. else
  7. for i = 1, n do
  8. a[n], a[i] = a[i], a[n]
  9. permutation_gen(a, n - 1)
  10. a[n], a[i] = a[i], a[n]
  11. end
  12. end
  13. end
  14. function permutations(a)
  15. local co = coroutine.create(function() permutation_gen(a) end)
  16. return function()
  17. local code, res = coroutine.resume(co)
  18. return res
  19. end
  20. end
  21. function permutations_wrap(a)
  22. return coroutine.wrap(function() permutation_gen(a) end)
  23. end
  24. for p in permutations({1, 2, 3}) do
  25. for i = 1, #p do io.write(p[i], " ") end
  26. io.write("\n")
  27. end
  28. print("----")
  29. for p in permutations_wrap({1, 2, 3}) do
  30. for i = 1, #p do io.write(p[i], " ") end
  31. io.write("\n")
  32. end

输出:

  1. 2 3 1
  2. 3 2 1
  3. 3 1 2
  4. 1 3 2
  5. 2 1 3
  6. 1 2 3
  7. ----
  8. 2 3 1
  9. 3 2 1
  10. 3 1 2
  11. 1 3 2
  12. 2 1 3
  13. 1 2 3

其中coroutine.warp(func)方法就是创建一个封装func的协程,然后返回一个调用该协程的函数。

lua coroutine的更多相关文章

  1. Lua Coroutine详解

    协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈,局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西.线程与协同程序的主要区别在于,一个具有多线程的程序可以同时运行几个线程 ...

  2. 【转】Lua coroutine 不一样的多线程编程思路

    Lua coroutine 不一样的多线程编程思路 Sunday, Apr 26th, 2009 by Tim | Tags: coroutine, Lua 上周末开始看<Lua程序设计> ...

  3. lua coroutine for iterator

    背景 前面的文章演示了使用闭包函数实现 状态的迭代器. 本文演示使用 coroutine来产生迭代器的例子. coroutine迭代器例子 -- 遍历二叉树 local binary_tree = { ...

  4. 生成lua的静态库.动态库.lua.exe和luac.exe

    前些日子准备学习下关于lua coroutine更为强大的功能,然而发现根据lua 5.1.4版本来运行一段代码的话也会导致 "lua: attempt to yield across me ...

  5. 理解 Lua 的那些坑爹特性

    按:最近看到了依云的文章,一方面,为Lua被人误解而感到十分难过,另一方面,也为我的好友, 依云没有能够体会到Lua的绝妙和优雅之处而感到很遗憾,因此我写了这篇文章,逐条款地说明了 依云理解中出现的一 ...

  6. C/C++ Lua Parsing Engine

    catalog . Lua语言简介 . 使用 Lua 编写可嵌入式脚本 . VS2010编译Lua . 嵌入和扩展: C/C++中执行Lua脚本 . 将C++函数导出到Lua引擎中: 在Lua脚本中执 ...

  7. 跨平台高效率Lua网络库 ( 同步形式的API ,底层是异步非阻塞)

    Joynet 项目地址:https://github.com/IronsDu/Joynet 介绍 high performance network library for lua, based on  ...

  8. Openresty Lua协程调度机制

    写在前面 OpenResty(后面简称:OR)是一个基于Nginx和Lua的高性能Web平台,它内部集成大量的Lua API以及第三方模块,可以利用它快速搭建支持高并发.极具动态性和扩展性的Web应用 ...

  9. Lua协程的一个例子

    很久没记录笔记了,还是养成不了记录的习惯 下面是来自 programming in lua的一个协程的例(生产者与用户的例子) 帖代码,慢慢理解 -- Programming in Lua Corou ...

随机推荐

  1. Flask实战第67天:Flask+Celery实现邮件和短信异步发送

    之前在项目中我们发送邮件和 短信都是阻塞的,现在我们来利用Celery来优化它们 官方使用文档: http://flask.pocoo.org/docs/1.0/patterns/celery/ re ...

  2. HDU 6373 Pinball

    Pinball Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total S ...

  3. jquery checkbox用法汇总

    来源:http://www.jb51.net/article/75717.htm 1.全选 ? 1 2 3 $("#btn1").click(function(){ $(" ...

  4. JZYZOJ 1542 [haoi2015]str 矩阵乘法 dp

    http://172.20.6.3/Problem_Show.asp?id=1542 dp+矩阵乘法思路hin好想,对于我这种题目稍微学术就几乎什么也不会的人来说唯一的难点在于读题,因为一心想着划水题 ...

  5. 【二分答案】【最大流】[HNOI2007]紧急疏散EVACUATE

    [HNOI2007]紧急疏散EVACUATE 题目描述 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一块空地:如果是'X',那么表示这是一面 ...

  6. bzoj 1433: [ZJOI2009]假期的宿舍

    1433: [ZJOI2009]假期的宿舍 Description Input Output Sample Input 1 3 1 1 0 0 1 0 0 1 1 1 0 0 1 0 0 Sample ...

  7. (转)Hadoop系列-IPC模型

    学习笔记Mark IPC 实现RPC的一种方法,具有快速.简单的特点. 它不像Sun公司提供的标准RPC包,基于Java序列化. IPC无需创建网络stubs和skeletons. IPC中的方法调用 ...

  8. Jenkins构建Maven多模块项目时,单独编译子模块,并且不触发构建其它模块

    一.Jenkins构建Maven多模块项目时,单独编译子模块 配置: 1.Root POM指向父pom.xml 2.Goals and options指定构建模块的参数:mvn -pl jsoft-w ...

  9. [典型漏洞分享]YS忘记密码机制设计存在缺陷,导致任意用户口令均可被修改【高】

    记录了安全测试过程中发现的一些典型的安全问题 YS忘记密码机制存在缺陷,可导致任意用户口令被修改[高] 问题描述: YS网站提供用户密码修改功能,当用户忘记密码时可通过该功能找回密码,但该修改密码的流 ...

  10. 原生js封装的一些jquery方法

    用js封装一些常用的jquery方法 记录一下 hasClass:判断是否有class function hasClass(ele, cls) { if (!ele || !cls) return f ...