Kotlin-协程原理(2)- 协程创建

95 阅读2分钟

juejin.cn/editor/draf…

我们知道协程体会被Kotlin编译器转换为以下代码
static final class LaunchUnderTheHoodKt$testLaunch$1 extends SuspendLambda implements Function2<CoroutineScope, Continuation<? super Unit>, Object> {
        int label;
        LaunchUnderTheHoodKt$testLaunch$1(Continuation $completion) {
            super(2, $completion);
        }

        @Nullable
        @Override
        public final Object invokeSuspend(@NotNull Object $result) {

        @Override
        public final Object invoke(@NotNull CoroutineScope p1, @Nullable Continuation p2) {}

        @NonNull
        @Override
        public final Continuation create(@Nullable Object value, @NotNull Continuation $completion) {}
    }
}
分析重点

我们知道LaunchUnderTheHoodKttestLaunchtestLaunch1表示协程体。那么创建了LaunchUnderTheHoodKttestLaunchtestLaunch1对象,也就是协程被创建了,所以只要关注底层如何触发create函数这个重点就可以了,有这个前提才就不至于在源码中迷失。

到GlobalScope.launch一探究竟
  1. GlobalScope.launch 扩展函数启动协程
public fun CoroutineScope.launch(//1
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)//2
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)//3
    coroutine.start(start, coroutine, block)//4
    return coroutine//5
}
  • 注释1:launch是CoroutineScope的扩展函数,EmptyCoroutineContext表示空上下,那么协程就是Dispatchers.Default线程池上执行;CoroutineStart表示启动方式,CoroutineStart.DEFAULT表示立即启动,block表示协程体,也就是LaunchUnderTheHoodKttestLaunchtestLaunch1对象;
  • 注释2:子协程继承父协程的上下文(例如Dispatchers),返回一个新的上下文;
  • 注释3:因为不是lazy启动,所以返回StandaloneCoroutine;
  • 注释4:传入启动模式、StandaloneCoroutine对象、协程体,开始启动协程;
  • 注释5:返回coroutine,其实是Job,具备控制协程的能力,例如取消协程;
  1. StandaloneCoroutine的父类是AbstractCoroutine,所以AbstractCoroutine.start启动协程
public abstract class AbstractCoroutine<in T>(
    parentContext: CoroutineContext,
    initParentJob: Boolean,
    active: Boolean
) : JobSupport(active), Job, Continuation<T>, CoroutineScope {
    //省略部分代码
    public fun <R> start(start: CoroutineStart, receiver: R, block: suspend R.() -> T) {
        start(block, receiver, this)//1
    }
    
//CoroutineStart类中
public enum class CoroutineStart {
    ......
    @InternalCoroutinesApi
    public operator fun <T> invoke(block: suspend () -> T, completion: Continuation<T>): Unit =
        when (this) {
            DEFAULT -> block.startCoroutineCancellable(completion)//2
            ATOMIC -> block.startCoroutine(completion)
            UNDISPATCHED -> block.startCoroutineUndispatched(completion)
            LAZY -> Unit // will start lazily
        } 
  • 注释1:触发CoroutineStart的invoke函数,有点意思吧,我当时还找半天,到底跳转哪里去了;
  • 注释2:前面我们知道,start的类型是DEFAULT,所以触发block.startCoroutineCancellable(completion);
  1. startCoroutineCancellable 负责创建协程、封装协程、启动协程
public fun <T> (suspend () -> T).startCoroutineCancellable(completion: Continuation<T>): Unit = runSafely(completion) {
    createCoroutineUnintercepted(completion).intercepted().resumeCancellableWith(Result.success(Unit))//1
}
  • 注释1:startCoroutineCancellable是扩展函数,任何协程体都可以调用,这里有三个动作,createCoroutineUnintercepted创建协程,intercepted负责封装协程,resumeCancellableWith启动协程;
  1. createCoroutineUnintercepted创建协程
public actual fun <T> (suspend () -> T).createCoroutineUnintercepted(
    completion: Continuation<T>
): Continuation<Unit> {//1
    val probeCompletion = probeCoroutineCreated(completion)
    return if (this is BaseContinuationImpl)
        create(probeCompletion)//2
    else
        createCoroutineFromSuspendFunction(probeCompletion) {
            (this as Function1<Continuation<T>, Any?>).invoke(it)
        }
}
  • 注释1:actual表示这是对createCoroutineUnintercepted的实现,不同平台有不同的实现,这是Java平台的实现;
  • 注释2:前面一直通过block的扩展函数来调用,所以这里的this就是协程体block,也就是LaunchUnderTheHoodKttestLaunchtestLaunch1,间接继承BaseContinuationImpl),所以会触发if分支的create,重点来了,create在LaunchUnderTheHoodKttestLaunchtestLaunch1被重写了
  1. LaunchUnderTheHoodKttestLaunchtestLaunch1.create创建协程对象
static final class LaunchUnderTheHoodKt$testLaunch$1 extends SuspendLambda implements Function2<CoroutineScope, Continuation<? super Unit>, Object> {
    ......
    @NonNull
    @Override
    public final Continuation create(@Nullable Object value, @NotNull Continuation $completion) {
        return (Continuation) new LaunchUnderTheHoodKt$testLaunch$1($completion);//1
    }
}

这里主要分析协程体的创建流程,关于如何启动,可以关注juejin.cn/editor/draf…

总结

协程的创建也就是LaunchUnderTheHoodKttestLaunchtestLaunch1对象的创建;

以上分析有不对的地方,请指出,互相学习,谢谢哦!