协程是比线程更小的一种执行单元,你可以认为是轻量级的线程,之所以说轻,其中一方面的原因是协程所持有的栈比线程要小很多,java当中会为每个线程分配1M左右的栈空间,而协程可能只有几十或者几百K,栈主要用来保存函数参数、局部变量和返回地址等信息。
我们知道,而线程的调度是在操作系统中进行的,而协程调度则是在用户空间进行的,是开发人员通过调用系统底层的执行上下文相关api来完成的,有些语言,比如nodejs、go在语言层面支持了协程,而有些语言,比如C,需要使用第三方库才可以拥有协程的能力。
由于线程是操作系统的最小执行单元,因此也可以得出,协成是基于线程实现的,协程的创建、切换、销毁都是在某个线程中来进行的。
使用协程是因为线程的切换成本比较高,而协程在这方面很有优势。
为什么协程的切换很廉价
关于这个问题,我找了很多资料,得到的答案都没有太高的说服力,我了解了一下线程切换的过程:
- 线程在进行切换的时候,需要将CPU中的寄存器的信息存储起来,然后读入另外一个线程的数据,这个会花费一些时间
- CPU的高速缓存中的数据,也可能失效,需要重新加载
- 线程的切换会涉及到用户模式到内核模式的切换,据说每次模式切换都需要执行上千条指令,很耗时。
协程的切换之所以快,可能的原因是:
- 在切换的时候,寄存器需要保存和加载的数据量比较小。
- 高速缓存可以有效利用
- 没有用户模式到内核模式的切换操作。
- 更有效率的调度,因为协程是非抢占式的,前一个协程执行完毕或者堵塞,才会让出CPU,而线程则一般使用了时间片的算法,会进行很多没有必要的切换(为了尽量让用户感知不到某个线程卡)。
有哪些协程的实现
目前协程有很多版本的实现,比如云风(原网易的研发总监,开发过《大话西游》、《梦幻西游》等知名游戏)的基于ucontext实现的coroutine,还有人用C语言语法switch-case来实现的。
网友评论