从源码认识协程

先上一张流程图
追踪源码前,先了解一些Kotlin高阶写法,方便阅读代码
  1. 高阶拓展函数 T.()

一种类似 (T) 效果的写法

class A() {
    fun testA(block: A.() -> Unit) {
        block(this)
    }
}

val a = A()
a.testA {
    this // 指的就是a
}
  1. operator关键字

(1) 重写 []

class A(){
    operator fun get(i:Int):String {
        when(i){
            1->"a"
            else ->""
        }
    } 
}

val a = A()
val value = a[1]

(2) 重写 +

class A(){
    operator fun plus(a:A):A{
    }
}

val value = A() + A() // 这个写法就是CoroutineContext的基础实现方法
  1. invoke的写法
class A(){
    fun invoke(i:Int)
}

val a = A()
a.invoke(1)
a(1)  // invoke可以省略
  1. kotlin的扩展方法编译成java时,会生成一个类,构造方法的参数就是 该类 加 扩展方法的参数

通过最简单的协程调用方法来追踪协程的源码执行流程
suspend fun testA() {
        
}

// 最简单的调用
 GlobalScope.launch {
     testA()
 }
  1. 拓展方法launch编译后被替换成
  1. 在BuildersKt和BuildersKt_Builders_commonKt 两个类之间相互调用

生成StandaloneCoroutine类,这个类的基类在注解说明了该类的作用:

协程构建器中协程实现的抽象基类。此类实现完成 Continuation、Job 和 CoroutineScope 接口。 它将继续的结果存储在作业的状态中。 此协程在完成之前等待子协程完成,并通过中间失败状态失败。

  1. 调用start方法,通过CoroutineStart创建Continuation(这个类实现挂起和取消挂起的关键作用)

调用CoroutineStart的invoke方法

图中有三个拓展函数,下面将分成三个点

补充:Continuation这个类,代表的就是一个状态机

基类唯一一个变量CoroutineContext,是一个链表,存在当前协程的所有状态;resumeWith,注解写的意思就是 恢复执行相应的协程,将成功或失败的结果作为最后一个暂停点的返回值。当调用一个suspend方法时,当前方法的协议就在该位置被挂起,等suspend方法内的代码被执行完后,调用resumeWith回调被挂起的位置取消挂起继续执行,就结果作为参数返回,具体代码如下

这里地方应该就是协程能够实现挂起,切换线程等待的巧妙之处,本质还是使用了callback的做法

  1. 调用CoroutineStart的invoke方法创建Continuation,调用Funtion2的扩展方方法startCoroutineCancellable,创建继承ContinuationImpl的实例
  1. 调用了ContinuationImpl的intercepter方法

context[ContinuationInterceptor] 返回是一个 CoroutineDispatcher,调用intercepetContinuation 返回 继承DispatchedTask 本质也是一个runnable

  1. 调用resumeCancellableWith 将任务塞到Dispatcher(这里实现线程切换)

由于我们一开始是lauch(CoroutineStart.DEFAULT)

  1. 调用Dispatchers.Default的dispathch方法,会进入到对应的线程池内,等待执行

被执行

runSafely方法内执行的是之前CoroutineDispatcher的run方法

  1. 开始执行我们的目标的业务代码

进而调用ContinuationImpl的resumeWith 进而调用最开始的invokeSuspend

通过Continuation这个状态机进而suspend方法的调用,当前方法的挂起和取消挂起

到这里就是一次完整的最简单的协程调用。当我们再协程里面继续通过关键字withContext,开启新的协程,其实本质就是再嵌套了一层上面的调用流程,唯一的不用就是不用再新建一个新的Continuation,而是把当前协程的Continuation继续往下传递,从而实现父协程可以控制子协程,并且子协程可以挂起父协程或取消挂起

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值