概念

协程的概念最核心的点就是函数或者一段程序能够被挂起,稍后再在挂起的位置恢复

挂起和恢复是开发者的程序逻辑自己控制的,协程是通过主动挂起出让运行权来实现协作的,因此它本质上就是在讨论程序控制流程的机制,这是最核心的点,任何场景下探讨协程都能落脚到挂起和恢复

协程与线程最大的区别在于,从任务的角度来看,线程一旦开始执行就不会暂停,直到任务结束,这个过程都是连续的线程之间是抢占式的调度,因此不存在协作问题

  • 挂起恢复。
  • 程序自己处理挂起恢复。
  • 程序自己处理挂起恢复来实现程序执行流程的协作调度。

因而协程的实现也可以按照是否开辟相应的调用栈来分类。

  • 有栈协程(Stackful Coroutine):每一个协程都有自己的调用栈,有点类似于线程的调用栈,这种情况下的协程实现其实很大程度上接近线程,主要的不同体现在调度上。
  • 无栈协程(Stackless Coroutine):协程没有自己的调用栈,挂起点的状态通过状态机或者闭包等语法来实现。

Kotlin的协程通常被认为是一种无栈协程的实现,它的控制流转依靠对协程体本身编译生成的状态机的状态流转来实现,变量保存也是通过闭包语法来实现的。不过,Kotlin的协程可以在挂起函数范围内的任意调用层次挂起,换句话说,我们启动一个Kotlin协程,可以在其中任意嵌套suspend函数,而这又恰恰是有栈协程最重要的特性之一。

调度过程中,根据协程调度权的转移目标的不同又可将协程分为对称协程和非对称协程。

  • 对称协程(Symmetric Coroutine):任何一个协程都是相互独立且平等的,调度权可以在任意协程之间转移。
  • 非对称协程(Asymmetric Coroutine):协程出让调度权的目标只能是它的调用者,即协程之间存在调用和被调用关系。

Receiver是一个被suspend修饰的挂起函数,这也是协程的执行体,我们不妨称它为协程体。

参数completion会在协程执行完成后调用,实际上就是协程的完成回调。

返回值是一个Continuation对象,由于现在协程仅仅被创建出来,因此需要通过这个值在之后触发协程的启动。

所谓协程的挂起其实就是程序执行流程发生异步调用时,当前调用流程的执行状态进入等待状态。请注意,挂起函数不一定真的会挂起,只是提供了挂起的条件