我们首先介绍一下什么是协程、然后详细介绍一下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. 连接SQLServer时,因启用连接池导致孤立事务的原因分析和解决办法

    本文出处:http://www.cnblogs.com/wy123/p/6110349.html 之前遇到过这么一种情况: 连接数据库的部分Session会出现不定时的阻塞,这种阻塞时长时短,有时候持 ...

  2. WCF备忘录一:服务端实例的生命周期

    示例代码下载地址:WCFDemo1Day 概述 客户端向WCF服务发出请求后,服务端会实例化一个Service对象(实现了契约接口的对象)用来处理请求,实例化Service对象以及维护其生命周期的方式 ...

  3. 「译」JUnit 5 系列:基础入门

    原文地址:http://blog.codefx.org/libraries/junit-5-basics/ 原文日期:25, Feb, 2016 译文首发:Linesh 的博客:JUnit 5 系列: ...

  4. StackExchange.Redis帮助类解决方案RedisRepository封装(字符串类型数据操作)

    本文版权归博客园和作者本人共同所有,转载和爬虫请注明原文链接 http://www.cnblogs.com/tdws/tag/NoSql/ 目录 一.基础配置封装 二.String字符串类型数据操作封 ...

  5. 初识ASP.NET MVC

    我们首先从创建ASP.NET MVC项目开始.打开Visual Studio,在文件菜单中选择新建-> 项目,然后在模板中选择Web,接着选择ASP.Net Web应用程序,更改项目名称,点击确 ...

  6. c# 九九乘法表

    static void Main(string[] args) { ; i < ; i++) { ; s <= i; s++) { Console.Write(s + "*&qu ...

  7. iOS项目开发中的知识点与问题收集整理①(Part 一)

    前言部分 注:本文并非绝对原创 大部分内容摘自 http://blog.csdn.net/hengshujiyi/article/details/20943045 文中有些方法可能已过时并不适用于现在 ...

  8. 关于python字符串连接的操作

    python字符串连接的N种方式 注:本文转自http://www.cnblogs.com/dream397/p/3925436.html 这是一篇不错的文章 故转 python中有很多字符串连接方式 ...

  9. extend

    这段时间在写一个预览图片的插件, 被我老大说了无数次了,不多说啥,说多了都是泪 昨天看着我的代码他说你用了extend,那你知道是什么意思吗 我只知道是扩展的意思,瞬间觉得自己弱爆了 真的 然后今天看 ...

  10. zepto/jQuery、AngularJS、React、Nuclear的演化

    写在前面 因为zepto.jQuery2.x.x和Nuclear都是为现代浏览器而出现,不兼容IE8,适合现代浏览器的web开发或者移动web/hybrid开发.每个框架类库被大量用户大规模使用都说明 ...