协程Coroutine原理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tgxallen/article/details/79631334
  • Coroutine原理

    提到coroutine就不得不先讲讲进程与线程,进程与线程都是操作系统可感知的,也就是说其调度完全是由操作系统来执行,不能通过人工参与。通常操作系统调度进程与线程主要有时间片轮询、优先级调度等方式。

    进程与线程是操作系统可感知的,当正在运行的线程时间片用光后,操作系统需要根据调度算法选择下一个线程到当前CPU运行。线程与进程的切换是由操作系统完成的,那么在线程与进程之间进行切换到底需要保存哪些状态,则需要研究进程与线程运行所需要的资源了。

    每一个进程运行在自己的虚拟地址空间,与其他进程互不干扰,进程维护着自己的1)进程地址空间 ;2)堆栈; 3)寄存器;4)堆;线程运行在进程中,线程运行需要:1)堆栈;2)寄存器;线程堆栈默认大小一般是1M或2M。进程上下文切换首先要切换地址空间然后保存寄存器状态,这个过程非常复杂,且相对耗时,线程切换相对进程切换要轻量的多,但是线程堆栈资源相对要求较高系统也算是不小的开销。在网络编程初期,解决高并发的方式是通过per connect per thread的方式,随着互联网络壮大也就引入了C10K的问题,如果依然采用per thread per connect就会导致系统在资源占用较大,线程上下文切换频繁,CPU资源占用也会绝大部分在线程切换上。因此后来引入了select,epoll等多路复用IO通信模型。但是通过回调的方式实现异步操作增加了代码的阅读难度。

    协程概念很早就提出来了,但是近几年才火起来,一方面是因为一些脚本语言开始在语言级支持协程还有GO语言的诞生,另外一方面,利用协程的同步方式达到高并发的,是开发更容易理解。协程相对于进程和线程来说对于操作系统来说是透明的,所以操作系统并不能直接操控协程,所以协程的上下文切换完全由用户态自己控制,另外由于操作系统不能感知到协程,所以协程不能主动的利用操作系统的多核特性,需要依赖于多进程或者多线程(线程主动绑定到CPU)。

    协程因为在用户态进行切换,所以要自己保存寄存器,保存寄存器主要是为了保存上下文状态。

 

  • Coroutine意义

    从高并发场景来说,Coroutine将原来通过事件循环编程的异步方式,转换成较容易接受的同步开发,与基于事件循环的网络通信模型对比来说性能在理论上并不会有多少提升。所以并不是用协程就会提高性能,还是那句话协程的好处首先是上下文切换在用户态执行,另外一点可以将并发中异步做法用同步实现。

 

  • ​Linux下如何是实现Coroutine

    ​现在python,GO等都已经在语言级支持协程了,但是C++和C目前还没有,可以用C++或者C实现协程。目前已经有的实现有不少,Boost库提供了两种实现,分别是stackless与stackfull。两者主要差别是是否有单独的栈来存放数据。如果想自己实现Coroutine,可以直接使用Linux提供的context系列函数,当然也可以使用古老的setjump/longjump方式,也可以使用汇编语言自己实现context上下文切换。

阅读更多

没有更多推荐了,返回首页