除了 python,C#, Lua 语言都支持 coroutine 特性。coroutine 与 goroutine 在名字上类似,都是可中断可恢复的协程,它们之间最大的不同是,goroutine 可能在多核上发生并行执行,但 coroutine 始终是顺序执行。也基于此,我们应该清楚 coroutine 适用于 IO 密集程序中,而 goroutine 在 IO 密集和 CPU 密集中都有很好的表现。不过话说回来,go 就一定比 python 快么,假如在完全 IO 并发密集的程序中,python 的表现反而更好,因为单线程内的协程切换效率更高。

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

协程:线程的对应方式来看:

  • N:1,Python 协程模式,多个协程在一个线程中切换。在 IO 密集时切换效率高,但没有用到多核
  • 1:1,Java 多线程模式,每个协程只在一个线程中运行,这样协程和线程没区别,虽然用了多核,但是线程切换开销大。
  • M:N,go 模式,多个协程在多个线程上切换,既可以用到多核,又可以减少切换开销。(当都是 cpu 密集时,在多核上切换好,当都是 io 密集时,在单核上切换好)。

python coroutine 特点

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

go goroutine 特点

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