协程(一)快速理解协程的定义和分类
来源:互联网 发布:怎样领取淘宝优惠券 编辑:程序博客网 时间:2024/06/05 10:38
协程的概念很早以前就被提出,很多语言也实现了协程,例如Erlang,Lua。不过我首次接触协程是在学习golang的过程中,当真正使用协程的时候就被它的优雅和高效所折服,这也埋下了自己对协程好奇的种子。随着接触许多C++协程库,例如云风的coroutine、腾讯的libco、魅族的libgo等,很多当时模糊的概念也逐渐清晰。
云风的coroutine代码简介,实现了非对称的stackful协程,非常适合用来入门。笔者fork了该库,并根据自己对协程工作原理的理解为该库添加了注释,详细可参考我的github.
协程的定义
在计算机科学中,例程(过程、函数、方法、子程序)被定义为操作的序列。例程的执行形成了父子关系,且孩子例程总是在父例程前结束。举例说明,main函数中调用函数func1,func1中调用函数func2,此时就形成了父子关系(main为func1的父例程,func1是func2的父例程),func2执行结束进行函数栈回退,然后func1继续执行直到结束后进行函数栈回退,最后main继续执行直到结束后进行函数栈回退并退出程序。
协程是例程(过程、函数、方法、子程序)的范化概念。协程和例程的主要区别是,协程通过保持执行状态可以能够明确的挂起和恢复,协程通过维护上下文提供了增强的控制流。
2004年Lua的作者Ana Lucia de Moura和Roberto Ierusalimschy发表的论文Revisiting Coroutines中,对协程进行了分类,论文中依照三个问题区分协程:
- 控制传递(Control-transfer)机制
- 协程是否为栈式(Stackful)构造
- 协程是否作为语言的第一类(First-class)对象提供
协程如何工作
如果协程像例程一样,那么函数栈将会随着每次调用而增长、并且从不退栈。跳转到中间某个协程则是不可能的,因为函数栈的栈顶才能进行退栈操作。
解决方法则是让每个协程拥有自己的栈和控制块(control-block)。在协程挂起前,该协程的non-volatile寄存器值(包括stack、instruction/program pointer)被保存在该协程对应的control-block中。新激活协程在恢复前,它在control-block中存储的寄存器值被恢复到CPU的寄存器中。
上下文切换无需系统权限,为协作式多任务提供了方便。协程提供了并行性,例如当程序在同时做多件事情时,相比于只用一个单独的控制流,协程可以更加简单而优雅的做到这一点。
控制传递机制
根据控制传递机制的不同区分出了对称协程和非对称协程。
非对称协程知道它的调用者,其在挂起时转让控制权给它的调用者,然后调用者根据算法调用其他非对称协程进行工作。相比之下,所有的对称协程都是等价的,控制权直接在对称协程之间进行传递,即对称协程在挂起时主动指明另外一个对称协程来接收控制权。
stackfulness
对比stackless协程,stackful协程可以在内部的嵌套函数中被挂起,在挂起点恢复执行。而stackless协程仅能在顶层部分被挂起。
first-class对象
协程被作为first-class对象提供,那么其可以作为参数被传递,由函数创建并返回,并存储在一个数据结构中供后续操作,也可以被开发者自由的维护。从上面的描述可以看到,first-class对象主要为协程提供了良好的表达力,方便开发者对协程进行操作。
如果没有stackfulness和irst-class对象的语义,协程的能力将被限制。
参考资料
《Coroutine - Wiki》
《理解Lua的Coroutine》
《协程(一)协程的定义与分类》
《一个”蝇量级”C语言协程库》
- 协程(一)快速理解协程的定义和分类
- 协程(一)协程的定义与分类
- 协程(一)协程的定义与分类
- 如何修改bug(一)-bug的分类和定义
- (18)投影变换的定义和分类
- 如何修改bug(一)——bug的分类和定义
- 金融资产的定义和分类
- Issue的分类和定义
- 文本分类入门(一)文本分类问题的定义
- 文本分类入门(一)文本分类问题的定义
- 文本分类入门(一)文本分类问题的定义
- 文本分类入门(一)文本分类问题的定义
- 放大器的指标定义和分类
- 放大器的指标定义和分类
- Linux:端口的定义和分类
- 注解分类和定义
- netty基础入门(一)定义理解
- 我对多线程的理解和分类
- Android中处理崩溃异常
- android string.xml 添加特殊字符
- 【腾讯Bugly干货分享】移动客户端中高效使用SQLite
- linux用yum安装jdk或yum组安装jdk只有java命令没有javac命令
- 使用动态脚本元素加载js
- 协程(一)快速理解协程的定义和分类
- Android launcher 初体验--app开机启动
- 将Go函数导入Lua中供lua调用
- java自动装箱拆箱深入剖析
- HDU 1358 KMP模板
- Spring JdbcTemplate
- 【约瑟夫环—数学策略】
- Android阅读源码的几种方法
- MySQL配置