Coroutine介绍

什么是coroutine?

在C++里coroutine就是一个函数,但是这个函数可以有多个进入点(entry point),并且可以像线程一样挂起和唤醒。Wiki上有更精确的描述:“coroutines are computer program components that generalize subroutines to allow multiple entry points for suspending and resuming execution at certain locations.”。函数拥有了多个进入点的能力之后就可以在执行到某个点A的时候将控制权交给另外一个coroutine ,然后再在某个合适的时间点从退出点A继续执行。这就是coroutine的挂起和唤醒。

但是不要混淆coroutine和线程。线程是OS管理的最小执行单元,线程挂起的时候,OS会将当前的程序计数器写入context中,以便将来唤醒时重置程序计数器。也就是说线程的唤醒是真真正正的,从哪里退出再从哪里开始。而在编程语言去实现coroutine的时候,语言一般是不会有能力去直接操作程序计数器的。Coroutine in C这篇文章里面给出了一种实现方式,本质上就是在函数里面用switch case语句来选择恢复点。也就是说每次要到达恢复点,程序必须从函数的入口点进入,然后通过switch case语句跳转到合适的地点。

为什么要有coroutine?

线程在做并发的时候有一个很大的瓶颈就是context switch。比如说线程A发了个异步读的请求async_read去读取某个IO,之后线程A就进入了漫长的等待时间。当然OS是聪明的,它不会让线程A就这么傻傻地等着然后耗尽时间片。一但线程进入了等待状态,OS就会将时间让给后面的线程,context switch就这么发生了。当线程数量比较少的时候,或者切换不是很频繁的时候,这个问题还不明显。但是在线程切换比较频繁的场景下,这个问题就比较头疼了。更有甚者有些线程的执行时间还没有context switch的时间长。

对于上述问题,最直观的思路就是从OS入手,如果你实力够强重新写个scheduler也是可以的。还有一个思路就是,尽可能有效地利用线程的时间片,让线程的每一个时间片都做满。这要求对线程内执行的函数要有更高的控制能力。不敢说coroutine就是为了这个场景而生的,但是coroutine确实可以解决线程频繁切换的问题。

如何实现?

Coroutine如何实现并没有太多的硬性规定。通用的实现方式有两种,分别是stackful和stackless。stackful最直观的方式就是Coroutin in C中所提到的Duff's Device的实现方式。由于coroutine每次切换的时候都是一次C的函数调用,那么和普通的函数调用一样,栈分配啊之类的都是少不了的,所以叫做stackful。由于stackful的实现方式比较浪费内存空间,那么自然而然地就会想到,能不能由程序自己来控制栈的分配呢?stackless的实现方式就是抛弃了原有的函数调用方式,由程序自己来控制coroutine的上下文切换。典型代表是云风的实现和boost::asio。

其它相关概念

 一般来讲两人个概念和coroutine紧密相关:routine和generator。和routine的区别在前面已经说过了,就不再多说。generator其实很简单,首先它是一coroutine的一种,其次它只会把控制权返回给它的调用者,最后它设计的用途是用来分批次地返回计算结果的。具体可以参考这篇文章。貌似javascript里面对generator的支持比较好。

参考文章

转载于:https://www.cnblogs.com/hughlo/archive/2013/05/25/3098665.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值