协程概念

协程,其实可以理解为一种特殊的程序调用。特殊的是在执行过程中,在子程序(或者说函数)内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。

它有两个特征:

  • 可中断,这里的中断不是普通的函数调用,而是类似CPU的中断,CPU在这里直接释放转到其他程序断点继续执行。
  • 可恢复,等到合适的时候,可以恢复到中断的地方继续执行。

和进程线程的区别

上面两个特点就导致了它相对于线程和进程切换来说极高的执行效率,为什么这么说呢?我们先老生常谈地说一下进程和线程。

  • 进程是操作系统资源分配的基本单位,线程是操作系统调度和执行的最小单位

这两句应该是我们最常听到的两句话,拆开来说,

  • 进程是程序的启动实例,拥有代码和打开的文件资源、数据资源、独立的内存空间。
  • 线程从属于进程,是程序的实际执行者,一个进程至少包含一个主线程,也可以有更多的子线程,线程拥有自己的栈空间。无论是进程还是线程,都是由操作系统所管理和切换的。

我们再来看协程,它又叫做微线程,但其实它和进程还有线程完全不是一个维度上的概念

  • 进程和线程的切换完全是用户无感,由操作系统控制,从用户态到内核态再到用户态
  • 而协程的切换完全是程序代码控制的,在用户态的切换,就像函数回调的消耗一样,在线程的栈内即可完成。

python协程的特点

  • 单线程内切换,适用于IO密集型程序中,可以最大化IO多路复用的效果。
  • 无法利用多核。
  • 协程间完全同步,不会并行。不需要考虑数据安全。
  • 用法多样,可以用在web服务中,也可用在pipeline数据/任务消费中

go协程的特点

  • 协程间需要保证数据安全,比如通过channel或锁。
  • 可以利用多核并行执行。
  • 协程间不完全同步,可以并行运行,具体要看channel的设计。
  • 抢占式调度,可能无法实现公平。

coroutine(python)和goroutine(go)的区别

coroutine 与 goroutine 在名字上类似,都是可中断可恢复的协程,它们之间最大的不同是,

  • goroutine 可能在多核上发生并行执行,但 coroutine 始终是顺序执行。

也基于此,我们应该清楚coroutine适用于IO密集程序中,而goroutine在 IO密集和CPU密集 中都有很好的表现。不过话说回来,go就一定比python快么,假如在完全IO并发密集的程序中,python的表现反而更好,因为单线程内的协程切换效率更高

从运行机制上来说,coroutine 的运行机制属于协作式任务处理, 程序需要主动交出控制权,宿主才能获得控制权并将控制权交给其他 coroutine。

  • 如果开发者无意间或者故意让应用程序长时间占用 CPU,操作系统也无能为力,表现出来的效果就是计算机很容易失去响应或者死机。goroutine 属于抢占式任务处理,已经和现有的多线程和多进程任务处理非常类似, 虽然无法控制自己获取高优先度支持。但如果发现一个应用程序长时间大量地占用 CPU,那么用户有权终止这个任务。