我们首先介绍一下什么是协程、然后详细介绍一下coroutine库,然后介绍一下协程的简单用法,最后介绍一下协程的复杂用法。

一、协程是什么?

  (1)线程

  首先复习一下多线程。我们都知道线程——Thread。每一个线程都代表一个执行序列。

  当我们在程序中创建多线程的时候,看起来,同一时刻多个线程是同时执行的,不过实质上多个线程是并发的,因为只有一个CPU,所以实质上同一个时刻只有一个线程在执行。

  在一个时间片内执行哪个线程是不确定的,我们可以控制线程的优先级,不过真正的线程调度由CPU的调度决定。

  (2)协程

  那什么是协程呢?协程跟线程都代表一个执行序列。不同的是,协程把线程中不确定的地方尽可能的去掉,执行序列间的切换不再由CPU隐藏的进行,而是由程序显式的进行。

  所以,使用协程实现并发,需要多个协程彼此协作。

二、resume和yeild的协作。

  resume和yeild的协作是Lua协程的核心。这边用一幅图描述一下,有一个大体的印象。对照下面的coroutine库的详细解释和最后的代码,应该可以搞清楚协程的概念了。

  注:这是在非首次resume协程的情况下,resume和yield的互相调用的情况。如果是首次resume协程,那么resume的参数会直接传递给协程函数。

三、coroutine库详解

(1)coroutine.create (f)

  传一个函数参数,用来创建协程。返回一个“thread”对象。

(2)coroutine.isyieldable ()

  如果正在运行的协程可以让出,则返回真。值得注意的是,只有主协程(线程)和C函数中是无法让出的。

(3)coroutine.resume (co [, val1, ···])

  这是一个非常重要的函数。用来启动或再次启动一个协程,使其由挂起状态变成运行状态。

  可以这么说,resume函数相当于在执行协程中的方法。参数Val1...是执行协程co时传递给协程的方法。

  首次执行协程co时,参数Val1...会传递给协程co的函数;

  再次执行协程co时,参数Val1...会作为给协程co中上一次yeild的返回值。

  不知道这句话大家理解了没,这是协程的核心。如果没理解也不用急,继续往下看,稍后我会详细解释。

  resume函数返回什么呢?有3种情况:

  1)、如果协程co的函数执行完毕,协程正常终止,resume 返回 true和函数的返回值。

  2)、如果协程co的函数执行过程中,协程让出了(调用了yeild()方法),那么resume返回true和协程中调用yeild传入的参数。

  3)、如果协程co的函数执行过程中发生错误,resume返回false与错误消息。

  可以看到resume无论如何都不会导致程序崩溃。它是在保护模式下执行的。

(4)coroutine.running ()

  用来判断当前执行的协程是不是主线程,如果是,就返回true。

(5)coroutine.status (co)

  返回一个字符串,表示协程的状态。有4种状态:

  1)、running。如果在协程的函数中调用status,传入协程自身的句柄,那么执行到这里的时候才会返回running状态。

  2)、suspended。如果协程还未结束,即自身调用了yeild或还没开始运行,那么就是suspended状态。

  3)、normal。如果协程Aresume协程B时,协程A处于的状态为normal。在协程B的执行过程中,协程A就一直处于normal状态。因为它这时候既不是挂起状态、也不是运行状态。

  4)、dead。如果一个协程发生错误结束,或正常终止。那么就处于dead状态。如果这时候对它调用resume,将返回false和错误消息。

(6)coroutine.wrap (f)

  wrap()也是用来创建协程的。只不过这个协程的句柄是隐藏的。跟create()的区别在于:

  1)、wrap()返回的是一个函数,每次调用这个函数相当于调用coroutine.resume()。

  2)、调用这个函数相当于在执行resume()函数。

  3)、调用这个函数时传入的参数,就相当于在调用resume时传入的除协程的句柄外的其他参数。

  4)、调用这个函数时,跟resume不同的是,它并不是在保护模式下执行的,若执行崩溃会直接向外抛出。

(7)coroutine.yield (···)

  使正在执行的函数挂起。

  传递给yeild的参数会作为resume的额外返回值。

   同时,如果对该协程不是第一次执行resume,resume函数传入的参数将会作为yield的返回值。

四、例子进阶。

(1)、例子1:简单实用resume、yield,如下:

coco = coroutine.create(function (a,b)
print("resume args:"..a..","..b)
yreturn = coroutine.yield()
print ("yreturn :"..yreturn)
end)
coroutine.resume(coco,,)
coroutine.resume(coco,)

输出:

resume args:,
yreturn :

(2)、例子2:简单使用wrap,如下:

coco2 = coroutine.wrap(function (a,b)
print("resume args:"..a..","..b)
yreturn = coroutine.yield()
print ("yreturn :"..yreturn)
end)
print(type(coco2))
coco2(,)
coco2()

输出:

function
resume args:,
yreturn :

很明显,wrap的使用更方便。

(3)、如果还没有足够的理解,且看我放大招,看这个例子:

function status()
print("co1's status :"..coroutine.status(co1).." ,co2's status: "..coroutine.status(co2))
end co1 = coroutine.create(function ( a )
print("arg is :"..a)
status()
local stat,rere = coroutine.resume(co2,"")
print("resume's return is "..rere)
status()
local stat2,rere2 = coroutine.resume(co2,"")
print("resume's return is "..rere2)
local arg = coroutine.yield("")
end)
co2 = coroutine.create(function ( a )
print("arg is :"..a)
status()
local rey = coroutine.yield("")
print("yeild's return is " .. rey)
status()
coroutine.yield("")
end)
--主线程执行co1,传入字符串“main thread arg”
stat,mainre = coroutine.resume(co1,"")
status()
print("last return is "..mainre)

用一个函数status()输出2个协程的状态,最后输出如下:

arg is :
co1's status :running ,co2's status: suspended
arg is :
co1's status :normal ,co2's status: running
resume's return is 3
co1's status :running ,co2's status: suspended
yeild's return is 4
co1's status :normal ,co2's status: running
resume's return is 5
co1's status :suspended ,co2's status: suspended
last return is

(4)、最后附一个云风在Lua5.3参考手册中给出的例子:

function foo(a)
print("foo", a)
return coroutine.yield( * a)
end co = coroutine.create(function ( a, b )
print("co-body", a, b)
local r = foo(a + )
print("co-body", r)
local r, s = coroutine.yield(a + b, a - b)
print("co-body", r, s)
return b, "end"
end) print("main", coroutine.resume(co, , ))
print("main", coroutine.resume(co, "r"))
print("main", coroutine.resume(co, "x", "y"))
print("main", coroutine.resume(co, "x", "y"))

输出如下:

co-body
foo
main true
co-body r
main true -
co-body x y
main true end
main false cannot resume dead coroutine

Lua的协程和协程库详解的更多相关文章

  1. 最强常用开发库总结 - JSON库详解

    最强常用开发库总结 - JSON库详解 JSON应用非常广泛,对于Java常用的JSON库要完全掌握.@pdai JSON简介 JSON是什么 JSON 指的是 JavaScript 对象表示法(Ja ...

  2. Python--urllib3库详解1

    Python--urllib3库详解1 Urllib3是一个功能强大,条理清晰,用于HTTP客户端的Python库,许多Python的原生系统已经开始使用urllib3.Urllib3提供了很多pyt ...

  3. Struts标签库详解【3】

    struts2标签库详解 要在jsp中使用Struts2的标志,先要指明标志的引入.通过jsp的代码的顶部加入以下的代码: <%@taglib prefix="s" uri= ...

  4. STM32固件库详解

    STM32固件库详解   emouse原创文章,转载请注明出处http://www.cnblogs.com/emouse/ 应部分网友要求,最新加入固件库以及开发环境使用入门视频教程,同时提供例程模板 ...

  5. MySQL5.6的4个自带库详解

    MySQL5.6的4个自带库详解 1.information_schema详细介绍: information_schema数据库是MySQL自带的,它提供了访问数据库元数据的方式.什么是元数据呢?元数 ...

  6. php中的PDO函数库详解

    PHP中的PDO函数库详解 PDO是一个“数据库访问抽象层”,作用是统一各种数据库的访问接口,与mysql和mysqli的函数库相比,PDO让跨数据库的使用更具有亲和力:与ADODB和MDB2相比,P ...

  7. STM32 HAL库详解 及 手动移植

    源: STM32 HAL库详解 及 手动移植

  8. 爬虫入门之urllib库详解(二)

    爬虫入门之urllib库详解(二) 1 urllib模块 urllib模块是一个运用于URL的包 urllib.request用于访问和读取URLS urllib.error包括了所有urllib.r ...

  9. Python爬虫系列-Urllib库详解

    Urllib库详解 Python内置的Http请求库: * urllib.request 请求模块 * urllib.error 异常处理模块 * urllib.parse url解析模块 * url ...

随机推荐

  1. DotNet 资源大全中文版(Awesome最新版)

    Awesome系列的.Net资源整理.awesome-dotnet是由quozd发起和维护.内容包括:编译器.压缩.应用框架.应用模板.加密.数据库.反编译.IDE.日志.风格指南等. 算法与数据结构 ...

  2. C语言用分别用递归和循环求数字的阶乘的方法

    以下代码均为 自己 实现,嘻嘻! 参考文章:http://blog.csdn.net/talk_8/article/details/46289683 循环法 int CalFactorial(int ...

  3. MVC5+EF6+AutoMapper+Bootstrap打造在线博客(1.1)

    DAL层的三个Model类: 字典表:CFDict 用户表:CFUser 用户爱好表:CFUserHobby(关联cfuser表和cfdict表) CFUser表和CFUserHobby表是一对多关系 ...

  4. Servlet3.0的可插拔功能

    如果说 3.0 版本新增的注解支持是为了简化 Servlet/ 过滤器 / 监听器的声明,从而使得 web.xml 变为可选配置, 那么新增的可插性 (pluggability) 支持则将 Servl ...

  5. Cobar + MySQL 技术验证(li)

    一.简介 Cobar是一个对数据进行拆分后进行分布式存储的产品,可以支持使用后台的 MySQL或者Oracle数据库,通过配置,将数据按照一定规则存储入不同的数据库中.即用分布式数据库代替了集中式数据 ...

  6. SpringMVC传值、转发、重定向例子

    练习接收页面参数值 使用request 使用@RequestParam注解 使用实体对象 练习向页面传出数据 使用HttpServletRequest和session 使用ModelAndView对象 ...

  7. Salesforce的sharing Rule 不支持Lookup型字段解决方案

    Salesforce 中 sharing rule 并不支持Look up 字段 和 formula 字段.但在实际项目中,有时会需要在sharing rule中直接取Look up型字段的值,解决方 ...

  8. 设计模式02迭代器(java)

    先贴代码,有空来写内容. 1.定义集合 import java.util.List; import java.util.ArrayList; //coollection是我自己定义的一个集合,因为要写 ...

  9. swift 学习笔记

    1. 数组中取出字符串的方法: 1)let string = "\arr[0]" 2) let string = String(stringInterpolationSegment ...

  10. SDK接入(1)之Android Facebook SDK接入

    SDK接入(1)之Android Facebook SDK接入 由于游戏已上线,且处于维护阶段,所以有空写写各种SDK接入过程和遇到的问题,也当作一种工作总结.SDK接入主流分为这么几类,登录.支付. ...