🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## coroutine概述 golang提供了语言级别的协程、coroutine是云风用C写的一个协程库、libco是腾讯开源的一个C++协程库。 在研究源码前,先弄清楚几个概念: 1.何为协程 2.协程种类 3.协程的使用和应用场景 ## 协程 vs 线程 * 线程是抢占式的,协程是非抢占式的。 * 线程数量通常不可以太多,而协程的数量可以非常多。如果线程的数量太多,那么大量线程的切换会影响性能。 * 协程的调度是应用代码自己实现的,而线程的调度是操作系统实现的。 ## 何为协程 ### 基础 1.协程可以理解成用户态的轻量级线程,切换由用户操作。 2.协程切换很快,不会陷入内核态。 3.协程拥有自己的寄存器上下文和栈, 协程调度切换时,将寄存器上下文和栈保存到其他地方,在切换回来的时候,恢复先前保存的寄存器上下文和栈。 ### 优点 1.**协程具有极高的执行效率 因为子程序切换不是线程切换,是由程序自身控制**,因此协程没有线程切换的开销, 多线程的线程数量越多,协程的性能优势就越明显。 2.**访问共享资源不需要多线程的锁机制**, 因为只有一个线程, 也不存在同时写变量冲突, 所以在协程中控制共享资源无需加锁, 只需要判断状态就好了,执行效率比多线程高很多, 而且代码编写难度也可以相应降低。 3.**以同步代码的方式写异步逻辑**, 但是协程实际上还是无法完全避免写异步回调,因为我们需要在异步API的基础上,结合协程库,开发出“同步”的API。 ### 缺点 无法利用多核资源, 除非和多进程配合 ## 协程种类 ### 有栈协程(Stackfull) & 无栈协程(Stackless) * `Stackless`类型不保存调用栈以及寄存器等信息,不属于真正的重入,因此一些局部变量都是无法使用的。 * `Stackfull`是真正的基于栈的重入,可以从某个嵌套的调用点上恢复执行。Stackfull协程在切换的时候,需要把当前的栈保存起来,以便在恢复的时候再次恢复执行,而`stackless`则不需要。 ### 连续栈 & 共享栈 ### 非对称协程 & 对称协程 协程按类型分为: * `非对称式协程`,协程之间有调用链关系,一个协程A释放控制权有2种方式 * 通过调用`yield`,将控制权返还给协程A的创建协程 * 通过调用`resume`,将控制权交给一个子协程 * `对称式协程`,与`非对称式协程`不同,各个协程之间可以互相转移控制权,类似于goto语句,这种方式,即使非常有经验的程序员也很难理清调用流程。同时该协程方式实现困难,性能不高。 业内实现的C/C++协程基本都采用`非对称`的协程方式。 ## 协程的使用和应用场景 对于一些比较上层的应用,例如即时通信软件,可能是比较合适的。 ### **进程、线程、协程的关系和区别:** * 进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。 * 线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。 * 协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。 libco上下文切换原理详解: https://zhuanlan.zhihu.com/p/27409164 有栈协程和无栈协程: https://www.jianshu.com/p/2782f8c49b2a ucontext-人人都可以实现的简单协程库: https://blog.csdn.net/qq910894904/article/details/41911175?spm=1001.2014.3001.5501 libco :https://blog.didiyun.com/index.php/2018/11/23/libco/ 参考连接:https://www.cyhone.com/articles/analysis-of-libco/ https://coolshell.cn/articles/10975.html https://www.jianshu.com/p/2782f8c49b2a libco https://github.com/yyrdl/libco-code-study/blob/master/readme/coctx_swap_S.md