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 doprint(i, a, b)coroutine.yield()end
endco2 = 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 dolocal value = io.read()print("produce: ", value)coroutine.yield(value)        --返回生产的值end
endconsumer = function(p)while true dolocal status, value = coroutine.resume(p);        --唤醒生产者进行生产print("consume: ", value)end
end--消费者驱动的设计,也就是消费者需要产品时找生产者请求,生产者完成生产后提供给消费者
producer = coroutine.create(produceFunc)
consumer(producer)

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

produceFunc = function()while true dolocal value = io.read()print("produce: ", value)coroutine.yield(value)        --返回生产的值end
endfilteFunc = function(p)while true dolocal status, value = coroutine.resume(p);value = value *100            --放大一百倍coroutine.yield(value)end
endconsumer = function(f, p)while true dolocal 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的值传递上。

转载于:https://www.cnblogs.com/daochong/p/7300895.html

Lua中的协同程序 coroutine相关推荐

  1. Lua 协同程序(coroutine)

    什么是协同(coroutine)? Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西. 协同是非常 ...

  2. Unity 中的协同程序

    今天咱就说说,协同程序coroutine.(这文章是在网吧敲的,没有unity,但是所有结论都被跑过,不管你信得过我还是信不过我,都要自己跑一下看看,同时欢迎纠错) 先说说啥是协程:协同程序是一个非常 ...

  3. unity控制程序等待_Unity 中的协同程序

    今天咱就说说,协同程序coroutine.(这文章是在网吧敲的,没有unity,但是所有结论都被跑过,不管你信得过我还是信不过我,都要自己跑一下看看,同时欢迎纠错) 先说说啥是协程:协同程序是一个非常 ...

  4. lua运行外部程序_Lua 协同程序(coroutine)

    coroutine.creat方法只要建立了一个协程 ,那么这个协程的状态默认就是suspend.使用resume方法启动后,会变成running状态:遇到yield时将状态设为suspend:如果遇 ...

  5. python3.4和3.5的区别_在3.4和3.5之间的python中的协同程序,我如何保持支持的兼容性?...

    我正在开发 python聊天机器人框架与asyncio.但是我看着 PEP-492,有新的语法,async /等待,最后它被接受. 我喜欢async / await语法,我想使用它.但我担心3.4的兼 ...

  6. C# WPF MVVM开发框架Caliburn.Micro IResult和协同程序⑥

    " 引言部分,总领全篇文章的中心内容." 01 - IResult and Coroutines 在前面,我提到了Actions概念的另一个引人注目的特性,称为协同程序.如果你以前 ...

  7. 使用asyncio协同程序的Web爬虫

    使用asyncio协同程序的Web爬虫 A. Jesse Jiryu Davis和Guido van Rossum A. Jesse Jiryu Davis是纽约MongoDB的一名工程师.他写了Mo ...

  8. 【笨木头Lua专栏】基础补充07:协同程序初探

    哎,周五晚上我都还这么努力看书,真是好孩子.(小若:不想吐槽了) 其实我都准备玩游戏看电影去的了,但是这书就摆在桌子上,而且正对着我,就想着,扫两眼吧. 结果一扫就不对劲了,因为这内容有点绕,有点小混 ...

  9. (转载)【笨木头Lua专栏】基础补充07:协同程序初探

    哎,周五晚上我都还这么努力看书,真是好孩子.(小若:不想吐槽了) 其实我都准备玩游戏看电影去的了,但是这书就摆在桌子上,而且正对着我,就想着,扫两眼吧. 结果一扫就不对劲了,因为这内容有点绕,有点小混 ...

最新文章

  1. 目标检测计算mAP,AP,Recall,Precision的计算方式和代码(YOLO和FastRCNN等)
  2. has been modified since the precompiled header
  3. 更改Eclipse Ctrl+1 的Idea 方式
  4. libnet TCP示例
  5. AjaxFileUploader上传插件 兼容性好
  6. PHP file_get_contents() 函数
  7. sklearn中digits手写字体数据集
  8. STM32 标准外设库(STM32F107)
  9. 标题中冒号的用法_如果论文题目中出现冒号,冒号前后两部分内容通常是?
  10. 鸿蒙系统能玩魔兽世界吗,魔兽世界TBC燃烧远征测试服,H英雄本的装备2小时内可以交易, 亲友们可以互相毛装备了...
  11. vim 配置(有插件)
  12. SQL select详解(基于选课系统)
  13. 如何设置阿里云Web应用攻击防护?
  14. 什么是架构?怎么进行架构设计
  15. 全新升级达内java高级互联网架构课|课件齐全
  16. 【python】No such file or directory的解决方法
  17. java简单代码实现_java的简单代码实现
  18. 你要整合资源,首先你得是一个有资源的人
  19. UE4 C++入门之路4-PostInitProperties函数详解(设置属性默认值的四种方法)
  20. 近乎不朽:Ed Yourdon

热门文章

  1. VC 运行时库 /MD、/MDd 和 /MT、/MTd
  2. 同一路由带参刷新,以及params和query两种方式传参的异同
  3. 德国精品软件推荐   压缩软件 WINRAR 个人版终于免费了。
  4. [起重机监测系统] 1、基于无线传输的桥式起重机的安全监测方案
  5. AutoFac文档9(转载)
  6. CCFollow和ActionCallFunc
  7. [20130706]传说中的中断风暴
  8. org.hibernate.AnnotationException: mappedBy reference an unknown target entity property
  9. 第十五章,读取txt文件(C++)
  10. Google分析language垃圾信息