Lua的协程和协程库详解
我们首先介绍一下什么是协程、然后详细介绍一下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的协程和协程库详解的更多相关文章
- 最强常用开发库总结 - JSON库详解
最强常用开发库总结 - JSON库详解 JSON应用非常广泛,对于Java常用的JSON库要完全掌握.@pdai JSON简介 JSON是什么 JSON 指的是 JavaScript 对象表示法(Ja ...
- Python--urllib3库详解1
Python--urllib3库详解1 Urllib3是一个功能强大,条理清晰,用于HTTP客户端的Python库,许多Python的原生系统已经开始使用urllib3.Urllib3提供了很多pyt ...
- Struts标签库详解【3】
struts2标签库详解 要在jsp中使用Struts2的标志,先要指明标志的引入.通过jsp的代码的顶部加入以下的代码: <%@taglib prefix="s" uri= ...
- STM32固件库详解
STM32固件库详解 emouse原创文章,转载请注明出处http://www.cnblogs.com/emouse/ 应部分网友要求,最新加入固件库以及开发环境使用入门视频教程,同时提供例程模板 ...
- MySQL5.6的4个自带库详解
MySQL5.6的4个自带库详解 1.information_schema详细介绍: information_schema数据库是MySQL自带的,它提供了访问数据库元数据的方式.什么是元数据呢?元数 ...
- php中的PDO函数库详解
PHP中的PDO函数库详解 PDO是一个“数据库访问抽象层”,作用是统一各种数据库的访问接口,与mysql和mysqli的函数库相比,PDO让跨数据库的使用更具有亲和力:与ADODB和MDB2相比,P ...
- STM32 HAL库详解 及 手动移植
源: STM32 HAL库详解 及 手动移植
- 爬虫入门之urllib库详解(二)
爬虫入门之urllib库详解(二) 1 urllib模块 urllib模块是一个运用于URL的包 urllib.request用于访问和读取URLS urllib.error包括了所有urllib.r ...
- Python爬虫系列-Urllib库详解
Urllib库详解 Python内置的Http请求库: * urllib.request 请求模块 * urllib.error 异常处理模块 * urllib.parse url解析模块 * url ...
随机推荐
- Oracle从文件系统迁移到ASM存储
环境:RHEL 6.4 + Oracle 11.2.0.4 需求:数据库存储由文件系统迁移到ASM 数据库存储迁移到ASM磁盘组 1.1 编辑参数文件指定新的控制文件路径 1.2 启动数据库到nomo ...
- 分布式服务协调员zookeeper - 应用场景和监控
zookeeper在分布式系统中作为协调员的角色,可应用于Leader选举.分布式锁.配置管理等服务的实现.以下我们从zookeeper提供的API.应用场景和监控三方面学习和了解zookeeper( ...
- JavaScript: 零基础轻松学闭包
本文面向初学者,大神轻喷. 闭包是什么? 初学javascript的人,都会接触到一个东西叫做闭包,听起来感觉很高大上的.网上也有各种五花八门的解释,其实我个人感觉,没必要用太理论化的观念来看待闭包. ...
- 实现跨浏览器html5表单验证
div:nth-of-type(odd){ float: left; clear: left; } .origin-effect > div:nth-of-type(even){ float: ...
- ASP.NET Core服务器综述
原文地址:Servers overview for ASP.NET Core By Tom Dykstra, Steve Smith, Stephen Halter, and Chris Ross A ...
- php中实现的一个curl批处理的实例
curl是利用URL语法在命令行方式下工作的开源文件传输工具 本文在php中实现了的一个curl批处理的实例. 代码如下: header("Content-Type:text/html;ch ...
- Android Time类 奇葩的设定
Android 的Time.MONTH默认是0-11表示1-12月,小白表示坑爹啊,浪费多少精力啊.
- JDBC 详解(转载)
原文链接:http://blog.csdn.net/cai_xingyun/article/details/41482835 什么是JDBC? Java语言访问数据库的一种规范,是一套API JDBC ...
- SharePoint Server2016的User Profile Services服务
前言SharePoint Server 的早期版本具有内置的 ForeFront Identity Manager (FIM) 副本,可在 SharePoint Server 服务器产品内运行.具 ...
- iOS 开发者账号到期续费流程
1.登录developer.apple.com,查看到期时间 2.到期提醒通知,点击Renew Membership续费(一般提前一个月提醒续费) 3.个人开发者账号续费需要支付 688人民币/年(9 ...