程序员人生 网站导航

浅谈我对协程的理解

栏目:框架设计时间:2015-01-16 08:49:37

我心中的协程

最近在研究网络服务框架方面的东西,发现了1个奇异的东西-协程。
1句话说明甚么是线程:协程是1种用户态的轻量级线程

1句话其实不能完全概括协程的全部,但是最少能让我们对协程这个概念有1个基本的印象。
从硬件发展来看,从最初的单核单CPU,到单核多CPU,多核多CPU,似乎已到了极限了,但是单核CPU性能却还在不断提升。server端也在不断的发展变化。如果将程序分为IO密集型利用和CPU密集型利用,2者的server的发展以下:
IO密集型利用: 多进程->多线程->事件驱动->协程
CPU密集型利用:多进程-->多线程

如果说多进程对多CPU,多线程对应多核CPU,那末事件驱动和协程则是在充分发掘不断提高性能的单核CPU的潜力。
以下的讨论如无特别说明,不斟酌cpu密集型利用。

异步 vs 同步

不管是线程还是进程,使用的都是同步进制,当产生阻塞时,性能会大幅度下降,没法充分利用CPU潜力,浪费硬件投资,更重要造成软件模块的铁板化,紧耦合,没法切割,不利于往后扩大和变化。不论是进程还是线程,每次阻塞、切换都需要堕入系统调用(system call),先让CPU跑操作系统的调度程序,然后再由调度程序决定该跑哪个进程(线程)。多个线程之间在1些访问互斥的代码时还需要加上锁,这也是致使多线程编程难的缘由之1。

现下流行的异步server都是基于事件驱动的(如nginx)。事件驱动简化了编程模型,很好地解决了多线程难于编程,难于调试的问题。异步事件驱动模型中,把会致使阻塞的操作转化为1个异步操作,主线程负责发起这个异步操作,并处理这个异步操作的结果。由于所有阻塞的操作都转化为异步操作,理论上主线程的大部份时间都是在处理实际的计算任务,少了多线程的调度时间,所以这类模型的性能通常会比较好。

总的说来,当单核cpu性能提升,cpu不在成为性能瓶颈时,采取异步server能够简化编程模型,也能提高IO密集型利用的性能。

协程 vs 线程

之前说道,协程是1种用户级的轻量级线程。协程具有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:

协程能保存上1次调用时的状态(即所有局部状态的1个特定组合),每次进程重入时,就相当于进入上1次调用的状态,换种说法:进入上1次离开时所处逻辑流的位置。

在并发编程中,协程与线程类似,每一个协程表示1个履行单元,有自己的本地数据,与其它协程同享全局数据和其它资源。目前主流语言基本上都选择了多线程作为并发设施,与线程相干的概念是抢占式多任务(Preemptive multitasking),而与协程相干的是协作式多任务

不论是进程还是线程,每次阻塞、切换都需要堕入系统调用(system call),先让CPU跑操作系统的调度程序,然后再由调度程序决定该跑哪个进程(线程)。
而且由于抢占式调度履行顺序没法肯定的特点,使用线程时需要非常谨慎地处理同步问题,而协程完全不存在这个问题(事件驱动和异步程序也有一样的优点)。

我们在自己在进程里面完成逻辑流调度,碰着io我就用非阻塞式的。那末我们便可以利用到异步优势,又可以免反复系统调用,还有进程切换酿成的开消,分分钟给你上几千个逻辑流不费力。这就是协程。

协程 vs 事件驱动

以nginx为代表的事件驱动的异步server正在横扫天下,那末事件驱动模型会是server端模型的终点吗?
我们可以深入了解下,事件驱动编程的模型。
事件驱动编程的架构是预先设计1个事件循环,这个事件循环程序不断地检查目前要处理的信息,根据要处理的信息运行1个触发函数。其中这个外部信息可能来自1个目录夹中的文件,可能来自键盘或鼠标的动作,或是1个时间事件。这个触发函数,可以是系统默许的也能够是用户注册的回调函数。

事件驱动程序设计侧重于弹性和异步化上面。许多GUI框架(如windows的MFC,Android的GUI框架),Zookeeper的Watcher等都使用了事件驱动机制。未来还会有其他的基于事件驱动的作品出现。

基于事件驱动的编程是单线程思惟,其特点是异步+回调。
协程也是单线程,但是它能让原来要使用异步+回调方式写的非人类代码,可以用看似同步的方式写出来。它是实现推拉互动的所谓非抢占式协作的关键。

总结

协程的好处:

  • 跨平台
  • 跨体系架构
  • 无需线程上下文切换的开消
  • 无需原子操作锁定及同步的开消
  • 方便切换控制流,简化编程模型
  • 高并发+高扩大性+低本钱:1个CPU支持上万的协程都不是问题。所以很合适用于高并发处理。

缺点:

  • 没法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.固然我们平常所编写的绝大部份利用都没有这个必要,除非是cpu密集型利用。
  • 进行阻塞(Blocking)操作(如IO时)会阻塞掉全部程序:这1点和事件驱动1样,可使用异步IO操作来解决
------分隔线----------------------------
------分隔线----------------------------

最新技术推荐