现在的位置: 首页 > 综合 > 正文

协程简介

2018年02月03日 ⁄ 综合 ⁄ 共 1341字 ⁄ 字号 评论关闭

关于协程的概念,其实由来已久,在介绍协程的概念之前先简单回顾下我们通常使用到的例程、线程等概念。

例程(Subroutine)

例程的概念类似于函数,但含义更为丰富一些。例程是某个系统对外提供的功能接口或服务的集合。比如操作系统的API、服务等就是例程;C语言运行时提供的标准库函数等也是例程。Pthreads库提供的一套线程相关的API也属于例程。通俗的理解,一个子例程就是一次子函数调用,只不过相对一般函数,例程的通用性和相对独立性都比较强。

协程(Coroutine)

协程,意思就是“协作的例程”(co-operative routines),最早由Melvin Conway在1963年提出并实现。跟主流程序语言中的线程不一样,线程实现的系统称之为抢占式多任务系统,而协程实现的多任务系统是协作式多任务系统。线程由于缺乏yield语义,所以运行过程中不可避免需要调度,休眠挂起,上下文切换等系统开销,还需要小心使用同步机制保证多线程正常运行。而协程的调度是程序自行管理的,不需要同步机制,协程之间的切换也只涉及到控制权的交换,相比较线程来说是非常轻便的。

协程与例程的区别

通俗的理解,一个子例程就是一次子函数调用,那么实际上协程就是类似于函数一样的程序组件。它们的重要区别在于,通常而言,例程只有一个调用入口起始点,返回之后就结束了,而协程入口既可以是起始点,也可以从上一个返回点继续执行,也就是说协程提供了 yield / resume的语义特性,即协程在执行过程中可以暂停,转而去执行其他的协程,同时可以在未来某个时刻点返回到上次暂停的地方继续往下执行。协程的最大威力也就在于此,比如利用协程的这种能力,我们可以轻易的实现想都不敢想的同步代码异步执行。再比如采用协程,我们也可以很容易的实现某种业务的状态机,而且可读性和可维护性大大的提高。

协程另外一个重要的特点就是:协程是作用在用户态,操作系统内核对于协程是毫无感知的,这样一来,协程的创建就类似于普通对象的创建,非常轻量级,从而使你可以在一个线程里面轻松创建数十万个协程,就像数十万次函数调用一样。可以想象一下,如果是在一个进程里面创建数十万个线程,结果该是怎样可怕。

进程、线程和协程

进程拥有自己独立的堆和栈,是系统资源管理的最小单位,进程由操作系统调度。
线程拥有自己独立的栈,共享堆,不共享栈,是系统调度的最小单位线程亦由操作系统调度。
协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示的调度,且协程的切换完全在用户态进行。

协程和线程的区别是:协程由于是程序完全自行管理协程的切换,极大的减少了进程/线程上下文的切换,避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。总体简而言之,本质上协程就是用户空间下的线程。

协程的实现库

Lua, Go等语言原生支持协程
Java依赖第三方库,例如最为著名的协程开源库Kilim
C标准库里的函数setjmp和longjmp可以用来实现一种协程。不幸的是,setjmp和longjmp的相当地难以实现。另外一种广为使用的C语言协程非标准库有 ucontext,网上绝大多数 C 协程库也是基于 ucontext 组件实现的。

抱歉!评论已关闭.