Lua中的协同程序 coroutine(转)
Lua中的协程和多线程很相似,每一个协程有自己的堆栈,自己的局部变量,可以通过yield-resume实现在协程间的切换。不同之处是:Lua协程是非抢占式的多线程,必须手动在不同的协程间切换,且同一时刻只能有一个协程在运行。并且Lua中的协程无法在外部将其停止,而且有可能导致程序阻塞。
协同程序(Coroutine):
三个状态:suspended(挂起,协同刚创建完成时或者yield之后)、running(运行)、dead(函数走完后的状态,这时候不能再重新resume)。
coroutine.create(arg):根据一个函数创建一个协同程序,参数为一个函数
coroutine.resume(co):使协同从挂起变为运行(1)激活coroutine,也就是让协程函数开始运行;(2)唤醒yield,使挂起的协同接着上次的地方继续运行。该函数可以传入参数
coroutine.status(co):查看协同状态
coroutine.yield():使正在运行的协同挂起,可以传入参数
resume函数的两种用途虽然都是使协同挂起,但还是有些许差异的,看下面这个例子:

coroutineFunc = function (a, b)
for i = 1, 10 do
print(i, a, b)
coroutine.yield()
end
end co2 = coroutine.create(coroutineFunc) --创建协同程序co2
coroutine.resume(co2, 100, 200) -- 1 100 200 开启协同,传入参数用于初始化
coroutine.resume(co2) -- 2 100 200
coroutine.resume(co2, 500, 600) -- 3 100 200 继续协同,传入参数无效 co3 = coroutine.create(coroutineFunc) --创建协同程序co3
coroutine.resume(co3, 300, 400) -- 1 300 400 开启协同,传入参数用于初始化
coroutine.resume(co3) -- 2 300 400
coroutine.resume(co3) -- 3 300 400

Lua中协同的强大能力,还在于通过resume-yield来交换数据:
(1)resume把参数传给程序(相当于函数的参数调用);
(2)数据由yield传递给resume;
(3)resume的参数传递给yield;
(4)协同代码结束时的返回值,也会传给resume
协同中的参数传递形势很灵活,一定要注意区分,在启动coroutine的时候,resume的参数是传给主程序的;在唤醒yield的时候,参数是传递给yield的。看下面这个例子:
co = coroutine.create(function (a, b) print("co", a, b, coroutine.yield()) end)
coroutine.resume(co, 1, 2) --没输出结果,注意两个数字参数是传递给函数的
coroutine.resume(co, 3, 4, 5) --co 1 2 3 4 5,这里的两个数字参数由resume传递给yield
Lua的协同称为不对称协同(asymmetric coroutines),指“挂起一个正在执行的协同函数”与“使一个被挂起的协同再次执行的函数”是不同的,有些语言提供对称协同(symmetric coroutines),即使用同一个函数负责“执行与挂起间的状态切换”。
注意:resume运行在保护模式下,因此,如果协同程序内部存在错误,Lua并不会抛出错误,而是将错误返回给resume函数。
以下是我个人的一点理解:
(1)resume可以理解为函数调用,并且可以传入参数,激活协同时,参数是传给程序的,唤醒yield时,参数是传递给yield的;
(2)yield就相当于是一个特殊的return语句,只是它只是暂时性的返回(挂起),并且yield可以像return一样带有返回参数,这些参数是传递给resume的。
为了理解上面两句话的含义,我们来看一下如何利用Coroutine来解决生产者——消费者问题的简单实现:

produceFunc = function()
while true do
local value = io.read()
print("produce: ", value)
coroutine.yield(value) --返回生产的值
end
end consumer = function(p)
while true do
local status, value = coroutine.resume(p); --唤醒生产者进行生产
print("consume: ", value)
end
end --消费者驱动的设计,也就是消费者需要产品时找生产者请求,生产者完成生产后提供给消费者
producer = coroutine.create(produceFunc)
consumer(producer)

这是一种消费者驱动的设计,我们可以看到resume操作的结果是等待一个yield的返回,这很像普通的函数调用,有木有。我们还可以在生产消费环节之间加入一个中间处理的环节(过滤器):

produceFunc = function()
while true do
local value = io.read()
print("produce: ", value)
coroutine.yield(value) --返回生产的值
end
end filteFunc = function(p)
while true do
local status, value = coroutine.resume(p);
value = value *100 --放大一百倍
coroutine.yield(value)
end
end consumer = function(f, p)
while true do
local status, value = coroutine.resume(f, p); --唤醒生产者进行生产
print("consume: ", value)
end
end --消费者驱动的设计,也就是消费者需要产品时找生产者请求,生产者完成生产后提供给消费者
producer = coroutine.create(produceFunc)
filter = coroutine.create(filteFunc)
consumer(filter, producer)

可以看到,我们在中间过滤器中将生产出的值放大了一百倍。
通过这个例子应该很容易理解coroutine中如何利用resume-yield调用来进行值传递了,他们像“调用函数——返回值”一样的工作,也就是说resume像函数调用一样使用,yield像return语句一样使用。coroutine的灵活性也体现在这种通过resume-yield的值传递上。
http://www.cnblogs.com/sifenkesi/p/3824321.html
Lua中的协同程序 coroutine(转)的更多相关文章
- Lua中的协同程序 coroutine
Lua中的协程和多线程很相似,每一个协程有自己的堆栈,自己的局部变量,可以通过yield-resume实现在协程间的切换.不同之处是:Lua协程是非抢占式的多线程,必须手动在不同的协程间切换,且同一时 ...
- Lua中的协同程序
[前言] 协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈.局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西.从概念上讲,线程与协同程序的主要区别在于,一个具有多个线程的 ...
- Lua 协同程序(coroutine)
什么是协同(coroutine)? Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西. 协同是非常 ...
- 【转】关于Unity协同程序(Coroutine)的全面解析
http://www.unity.5helpyou.com/2658.html 本篇文章我们学习下unity3d中协程Coroutine的的原理及使用 1.什么是协调程序 unity协程是一个能暂停执 ...
- Unity 中的协同程序
今天咱就说说,协同程序coroutine.(这文章是在网吧敲的,没有unity,但是所有结论都被跑过,不管你信得过我还是信不过我,都要自己跑一下看看,同时欢迎纠错)先说说啥是协程:协同程序是一个非常让 ...
- Lua 学习之基础篇九<Lua 协同程序(Coroutine)>
引言 讲到协程,首先来介绍一下线程和协程的区别 lua协程和多线程 相同之处:拥有自己独立的桟.局部变量和PC计数器,同时又与其他协程共享全局变量和其他大部分东西 不同之处:一个多线程程序可以同时运行 ...
- 【转】Unity中的协同程序-使用Promise进行封装(三)
原文:http://gad.qq.com/program/translateview/7170967 译者:崔国军(飞扬971) 审校:王磊(未来的未来) 在这个系列的最后一部分文章,我们要通过 ...
- 【转】Unity中的协同程序-使用Promise进行封装(一)
原文:http://gad.qq.com/program/translateview/7170767 译者:陈敬凤(nunu) 审校:王磊(未来的未来) 每个Unity的开发者应该都对协同程序非 ...
- 【转】Unity中的协同程序-使用Promise进行封装(二)
原文:http://gad.qq.com/program/translateview/7170970 译者:王磊(未来的未来) 审校:崔国军(飞扬971) 在上一篇文章中,我们的注意力主要是 ...
随机推荐
- eclipse配置本地服务
1.下载安装eclipse 2.下载tomcat文件,并解压 3.下载tomcat插件 com.sysdeo.eclipse.tomcat_3.3.0 将com.sysdeo.eclipse.tomc ...
- WIN内核线程池函数
线程池 (本章节中样例都是用 VS2010 编译调试的) 线程池编写必须在 Windows Vista 操作系统(以及以上版本号的操作系统)下,且 C++ 编译器版本号至少是 VS2008 线程池的功 ...
- TensorFlow 学习(十)—— 工具函数
1. 基本 tf.clip_by_value() 截断,常和对数函数结合使用 # 计算交叉熵 crose_ent = -tf.reduce_mean(tf.log(y_*tf.clip_by_valu ...
- 关于java项目与web项目中lib包的那点事
一.在java项目中如何引入外部jar包:1.在我们的java项目下新建一个lib文件夹:2.将我们需要引入的jat包复制到lib文件夹下:3.选中我们lib包下的jar,右键选择Build Path ...
- yii2框架学习一 yii安装与常见问题
1 安装安装有两种 cpmposer 喝归档文件 安装 这里采用的归档文件安装 归档文件安装分为两种 基础末班和高级模板,这里采用高级模板 在官网或者yii-china 下载归档文件 解 ...
- POJ 3904(容斥原理)
Sky Code Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 1750 Accepted: 545 Descripti ...
- Multiple address space mapping technique for shared memory wherein a processor operates a fault handling routine upon a translator miss
Virtual addresses from multiple address spaces are translated to real addresses in main memory by ge ...
- 微信公众平台消息接口开发(26)从Hello2BizUser文本到subscribe事件
微信公众平台 微信公众平台开发模式 消息接口 企业微信公众平台 Hello2BizUser subscribe 订阅事件 作者:方倍工作室 原文:http://www.cnblogs.com/txw1 ...
- Windows下Apache+MySQL+PHP快速配置的几种方法
Apache MySQL PHP Windows WAMP 1.易思EasySiteServer服务器集成环境 v1.0 (推荐) 尔创互联为推广其ESPCMS而开发的一个小东东,很好用.零配置,完 ...
- 使用CMD实现批量重命名[转]
关键字:cmd DOS 批处理 批量 重命名 作者:lifesinger地址:http://www.cnblogs.com/txw1958/archive/2012/12/24/cmd-batch-r ...