协同程序与线程差不多,也就是一条执行序列:有自己独立的栈、局部变量、指令指针,以及和其他协同程序共享的全局变量和其他大部分东西。

两者区别在于:一个多线程的程序可以同时运行几个线程,而协同程序却需要彼此协作地运行。

一个具有多个协同程序的程序在任意时刻只能运行一个协同程序,而且正在运行的协同程序只会在其显式地要求挂起时,它的执行才会暂停。

  协同程序是一个强大的解决方案,同样地它的几种主要用法也比较复杂。

  Lua将所有关于协同程序的函数放在一个名为corouting的table里。create函数用于创建新的协同程序,它只有一个参数(函数)。

create会返回一个thread类型的值,表示新的协同程序。通常create的参数是一个匿名函数:

co = coroutine.create(function () print("hi") end)
print(co) -->thread:0x8071d98

一个协同程序可以处于4个状态:挂起,运行,死亡,正常。

可以用函数status检查它的状态:

print (coroutine.status(co))         -->suspended

函数resume用于启动一个协同程序的执行,并将其状态由挂起转为运行:

coroutine.resume(co)         --> hi

协同程序打印了“hi”就终止了,协同程序的状态处于死亡状态,再也无法返回了。

协同程序的真正强大之处在于函数yield的使用上,它可以让一个运行中的程序挂起,而之后再恢复它的运行。

co = coroutine.create(function ()
for i = , do
print("co",i)
coroutine.yield()
end
end)

现在唤醒这个协同程序时,它就会开始执行,直到第一个yield:

coroutine.resume(co)        -->co  1

此时检查它的状态,就会看到它处于挂起状态。可以再次恢复其运行。

从协同程序的角度看,所有在它挂起时发生的轰动都发生在yield调用中。

当恢复协同程序的执行时,对于yield的调用才最终返回。然后协同程序继续它的执行,直到下一个yield调用或执行结束:

coroutine.resume(co)        -->co  2
coroutine.resume(co) -->co 3
...
coroutine.resume(co) -->co 10
coroutine.resume(co) --什么都不打印

到最后一次调用,协同程序已经返回。这时协同程序处于死亡状态。再resume就会返回false及一条错误消息:

print (coroutine.resume(co))
--> false cannot resume dead coroutine

请注意,resume是在保护模式中运行的。因此如果在一个协同程序的执行中发生任何错误

lua是不会显示错误消息的,而是将执行权返回给resume调用。

当一个协同程序A唤醒另一个协同程序B时,A就处于一个特殊状态,不是挂起,也不是运行。称为正常状态。

Lua的协同程序还有一个很有用的机制,可以通过一对resume-yield来交换数据。

第一次resume时,没有yield在等待它,所有传给resume的额外参数都将视为协同程序主函数的参数。

co = coroutine.create(function (a,b,c)
print("co",a,b,c+ )
end)
coroutine.resume(co,,,) -->co 1 2 5

在resume的返回内容中,第一个值为true表示没有错误,而后面所有的值都是对应yield转入的参数。

co = coroutine.create(function(a,b)
coroutine.yield(a+b,a-b)
end)
print(coroutine.resume(co,,)) -->true 30 10

与此对应的是,yield返回的额外值就是对应resume传入的参数:

co = coroutine.create(function (x)
print("co1",x)
print("co2",coroutine.yield())
end)
coroutine.resume(co,"hi") -->co1 hi
coroutine.resume(co,,) -->co2 4 5

最后,当一个协同程序结束时,它的主函数所返回的值都将作为对应resume的返回值:

co = coroutine.create(function ()
return ,
end)
print(coroutine.resume(co)) -->true 6 7

很少在一个程序中使用所有这些功能,但是每种功能各有其用途。

Lua提供的是一种“非对称的协同程序”。也就是Lua提供了两个函数来控制协同程序,一个用于挂起,一个用于恢复。

而其它一些语言提供的则是“对称的协同程序”,切换执行权都只有一个函数。

一个协同程序只能在它没有调用其他函数时,才可以挂起执行。换句话说,只有协同程序的主函数才能调用类似于yield这样的函数。

chapter9_1 协同程序的更多相关文章

  1. Lua 学习笔记(九)协同程序(线程thread)

    协同程序与线程thread差不多,也就是一条执行序列,拥有自己独立的栈.局部变量和命令指针,同时又与其他协同程序共享全局变量和其他大部分东西.从概念上讲线程与协同程序的主要区别在于,一个具有多个线程的 ...

  2. Unity3D协同程序(Coroutine)

    摘要下: 1. coroutine, 中文翻译"协程".这个概念可能有点冷门,不过百度之,说是一种很古老的编程模型了,以前的操作系统里进程调度里用到过,现在操作系统的进程调度都是根 ...

  3. 【转】Unity中的协同程序-使用Promise进行封装(三)

    原文:http://gad.qq.com/program/translateview/7170967 译者:崔国军(飞扬971)    审校:王磊(未来的未来) 在这个系列的最后一部分文章,我们要通过 ...

  4. 【转】Unity中的协同程序-使用Promise进行封装(二)

    原文:http://gad.qq.com/program/translateview/7170970 译者:王磊(未来的未来)    审校:崔国军(飞扬971)   在上一篇文章中,我们的注意力主要是 ...

  5. 【转】Unity中的协同程序-使用Promise进行封装(一)

    原文:http://gad.qq.com/program/translateview/7170767 译者:陈敬凤(nunu)    审校:王磊(未来的未来) 每个Unity的开发者应该都对协同程序非 ...

  6. 【转】关于Unity协同程序(Coroutine)的全面解析

    http://www.unity.5helpyou.com/2658.html 本篇文章我们学习下unity3d中协程Coroutine的的原理及使用 1.什么是协调程序 unity协程是一个能暂停执 ...

  7. Lua中的协同程序 coroutine

    Lua中的协程和多线程很相似,每一个协程有自己的堆栈,自己的局部变量,可以通过yield-resume实现在协程间的切换.不同之处是:Lua协程是非抢占式的多线程,必须手动在不同的协程间切换,且同一时 ...

  8. Unity 中的协同程序

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

  9. 9. MonoBehaviour.StartCoroutine 开始协同程序

    function StartCoroutine (routine : IEnumerator) : Coroutine 描述:开始协同程序. 一个协同程序在执行过程中,可以在任意位置使用yield语句 ...

随机推荐

  1. CodeForces 711C Coloring Trees

    简单$dp$. $dp[i][j][k]$表示:前$i$个位置染完色,第$i$个位置染的是$j$这种颜色,前$i$个位置分成了$k$组的最小花费.总复杂度$O({n^4})$. #pragma com ...

  2. 编译 ORB_SLAM2 (一)

    之前有记录关于ORB_SLAM的第一个版本的编译,每次就是要编译程序,都会遇到很多问题,并不是所谓的按照教程来就一定能编译成功,所以这一次编译也遇到了很多问题.百度的时候也看到网上有很多相似的问题,但 ...

  3. Unity性能优化——LOD技术

    LOD,中文名多层次细节,是游戏中最常用的技术,它按照模型的位置和重要程度决定物体渲染的资源分配,降低非重要物体的面数和细节度,从而获得高效率的渲染运算.今天我们来实现使用它来做一个简单的优化例子. ...

  4. DrawerLayout,ToolBar 和 TabHost 的使用

    ActionBar 定义起来不方便 toolbar: 最重要的特性,显示menu菜单,右上角三个点的菜单按钮,使用灵活 使用:1,布局文件,包裹LinearLayout 放imageView, 或者I ...

  5. Python数据预处理—训练集和测试集数据划分

    使用sklearn中的函数可以很方便的将数据划分为trainset 和 testset 该函数为sklearn.cross_validation.train_test_split,用法如下: > ...

  6. Mac下Cordova开发环境搭建

    xcode下载 从Mac App Store 下载Xcode,只需要在Store键入Xcode,下载第一个就ok了 cordova安装与配置 cordova需要node安装,使用Safari打开nod ...

  7. HAProxy 代理负载均衡

    HAProxy HAProxy是免费 高效 可靠的高可用及负载均衡解决方案,该软件非常适合于处理高负载站点的七层数据请求,HAProxy的工作模式使其可以非常容易且安全地集成到我们现有的站点架构中.使 ...

  8. python 基础学习1

    1.注释 与shell一样,python也是以#开始为注释语句 2.运算符 + - * / // ** python中有2种除法:单斜杠是普通除法,双斜杠是浮点数除法(结果四舍五入) < < ...

  9. Linux镜像资源收集

    1.企业 搜狐开源镜像站: http://mirrors.sohu.com/ 网易开源镜像站: http://mirrors.163.com/ 阿里开源镜像站: http://mirrors.aliy ...

  10. docker安装升级linux内核(2.6.32->3.12.17)

    1.内核升级环境准备 #查看已经安装的和未安装的软件包组,来判断我们是否安装了相应的开发环境和开发库:yum grouplist#一般是安装这两个软件包组,这样做会确定你拥有编译时所需的一切工具yum ...