协程与例程

协程(coroutine)技术是一种程序控制机制,早在上世纪60年代就已提出,用它可以很方便地实现协作式多任务。

协程是一种程序组件,是由子例程的概念泛化而来的,子例程只有一个入口点且只返回一次,而协程允许多个入口点,可以在指定位置挂起和恢复执行。

被广为引用的协程定义:

•协程的本地数据在后续调用中始终保持

•协程在控制离开时暂停执行,当控制再次进入时只能从离开的位置继续执行

在协程中,控制可以从当前执行上下文跳转到程序的其它位置,并且可以在之后的任意时刻恢复当前执行上下文,控制从跳出点处继续执行。这种行为与Continuation类似,但协程相比之下更容易理解,某些情况下还更加高效。

熟悉C/C++语言的人都知道,一个例程也就是一个函数。当我们调用一个函数时,执行流程进入函数;当函数执行完成后,执行流程返回给上层函数或例程。期间,每个函数执行共享一个线程栈;函数返回后栈顶的内容自动回收。这就是例程的特点,也是现代操作系统都支持这种例程方式。

协程与例程相对,从抽象的角度来说,例程只能进入一次并返回一次,而协程可能进入多次并返回多次。

void fun(int val)
{
    int a=0;    //1
    int b=0;    //2
    int c=a+b;  //3
}
如果上面的代码是一个例程,那么它只能把 1、2、3 依次执行后,才返回。如果是协程,它可能在 1 处暂停,然后在某个时刻从 2 处继续执行;接着在 2 处执行完之后暂停,然后在另外一个时刻从 3 处继续执行。

调用栈

我们传统上理解的函数,概念上也叫做子例程,是通过调用栈来传递调用关系的。协程则是比子例程更一般化的概念。子例程的调用是LIFO,它的启动位置是唯一入口,且只能返回一次;而协程允许有多个入口,且可以返回多次,你可以在特定的地方暂停和重新执行它。

上下文切换

上下文切换最早是指进程的上下文切换(context switch),它发生在内核态。内核调度器会对每个CPU上执行的进程进行调度(scheduling),以保证每个进程都能分到CPU时间片。当一个进程的时间片用完,或被中断后,内核将保存该进程的运行状态(即上下文),将其存入运行队列(run queue),同时让新的进程占用CPU。进程的上下文切换包括内存地址空间、内核态堆栈和硬件上下文(CPU寄存器)的切换,所以代价很高(具体参阅UTLK进程一章)。

由于进程切换开销大,所以设计了线程。Linux 2.6内核的clone()系统调用已经支持创建内核级线程,且发布了内核线程库pthread。在同一进程内的线程可以共享进程的地址空间,线程仅需要维护自己的寄存器、栈和线程相关的变量。不过内核线程的调度仍然需要由内核完成,这需要进行用户态和内核态的模式切换,至少包括堆栈和内存映射的切换。而且,不同进程之间的线程切换,有可能会还会导致进程切换,所以代价还是不小。

为了进一步减小内核态线程上下文切换的开销,于是又有了用户态线程设计,即纤程(Fiber)。纤程的调度可以由程序或线程库来完成,这样纤程上下文切换的开销比内核级线程切换要小得多。一个线程能拥有一个或多个纤程(Fiber)。这就是用户线程的一个实现。纤程间的调度都是在用户空间内完成的。

线程的调度,通常是由操作系统的线程调度器完成,在现代OS中,通常使用抢占式调度策略。而纤程的调用,完全依赖于程序员自己,即实现一种合作式调度,只有在主动提出切换时,才会进行切换。

要自己实现fiber,主要是保存线程上下文。注意要保存的信息有:各个寄存器,栈顶和栈底,异常信息,浮点寄存器。

锁机制

进程、线程、协程的设计,都是为了并发任务能够更好的利用CPU资源,协程可以作为进程和线程的有力补充。由于我们可以在用户态调度协程任务,所以,我们可以把一组互相依赖的任务设计成协程。这样,当一个协程任务完成之后,可以手动进行任务调度,把自己挂起(yield),切换到另外一个协程执行。这样,由于我们可以控制程序主动让出资源,很多情况下将不需要对资源加锁。


总的看来,协程有三个好处:

  • 避免了传统的函数调用栈,使得无限递归成为可能
  • 用户态的线程调度,极大降低上下文切换的开销,使得近乎无限并发成为可能
  • 由于可以在用户态进行手工线程调度,这样可以避免锁机制

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值