kotlin协程启动源码分析

参考文章

概念:

CoroutineScope

 * Defines a scope for new coroutines. Every **coroutine builder** (like [launch], [async], etc)
 * is an extension on [CoroutineScope] and inherits its [coroutineContext][CoroutineScope.coroutineContext]
 * to automatically propagate all its elements and cancellation.
 * 
定义新协程的范围。每个协程构建器(如launch 、 async等)都是CoroutineScope的扩展,并继承其coroutineContext以自动传播其所有元素并取消。

 * Every coroutine builder (like [launch], [async], etc)
 * and every scoping function (like [coroutineScope], [withContext], etc) provides _its own_ scope
 * with its own [Job] instance into the inner block of code it runs.
 * By convention, they all wait for all the coroutines inside their block to complete before completing themselves,
 * thus enforcing the structured concurrency. See [Job] documentation for more details.
 * 
每个协程构建器(如launch 、 async等)和每个作用域函数(如coroutineScope 、 withContext等)都在其运行的内部代码块中提供自己的范围和其自己的Job实例。按照惯例,它们 都等待其块内的所有协程完成后  再完成自己,从而 强制执行结构化并发。

常规代码启动协程

        CoroutineScope(Dispatchers.IO).launch {
        
         }

附上kotlin bytecode decomplie代码

      BuildersKt.launch$default(CoroutineScopeKt.CoroutineScope((CoroutineContext)Dispatchers.getIO()), (CoroutineContext)null, (CoroutineStart)null, (Function2)(new Function2((Continuation)null) {
         int label;

         @Nullable
         public final Object invokeSuspend(@NotNull Object var1) {
            Object var2 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
            switch(this.label) {
            case 0:
               ResultKt.throwOnFailure(var1);
               return Unit.INSTANCE;
            default:
               throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
            }
         }

         @NotNull
         public final Continuation create(@Nullable Object value, @NotNull Continuation completion) {
            Intrinsics.checkNotNullParameter(completion, "completion");
            Function2 var3 = new <anonymous constructor>(completion);
            return var3;
         }

         public final Object invoke(Object var1, Object var2) {
            return ((<undefinedtype>)this.create(var1, (Continuation)var2)).invokeSuspend(Unit.INSTANCE);
         }
      }), 3, (Object)null);
      

launch启动kotlin源码实现如下:

参数:
context - 协程的CoroutineScope.coroutineContext上下文的附加内容。
start - 协程启动选项。默认值为CoroutineStart.DEFAULT 。
block - 将在提供的范围的上下文中调用的协程代码。

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
// 1.为新协程创建上下文。它在没有指定其他调度程序或ContinuationInterceptor时安装Dispatchers.Default ,
//并添加对调试工具的可选支持(打开时)。
    val newContext = newCoroutineContext(context)  
    //2 创建coroutine ,一般是StandaloneCoroutine
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
        //3 启动协程, CoroutineStart.DEFAULT 默认使用startCoroutineCancellable 。
    coroutine.start(start, coroutine, block)
    return coroutine
}

CoroutineScope扩展函数launch

1.newCoroutineContext

@ExperimentalCoroutinesApi
public actual fun CoroutineScope.newCoroutineContext(context: CoroutineContext): CoroutineContext {
    val combined = coroutineContext + context
    val debug = if (DEBUG) combined + CoroutineId(COROUTINE_ID.incrementAndGet()) else combined
    return if (combined !== Dispatchers.Default && combined[ContinuationInterceptor] == null)
        debug + Dispatchers.Default else debug
}

1.会将launch方法传入的context与CoroutineScope中的context组合起来
2.如果combined中没有拦截器,会传入一个默认的拦截器,即Dispatchers.Default,这也解释了为什么我们没有传入拦截器时会有一个默认切换线程的效果

2.创建Continuation

  		 val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)

默认情况下,我们会创建一个StandloneCoroutine
值得注意的是,这个coroutine其实是我们协程体的complete,即成功后的回调,而不是协程体本身
然后调用coroutine.start,这表明协程开始启动了

3.协程启动

 coroutine.start(start, coroutine, block)

其实调用的是

//类似于startCoroutineCancellable ,但用于已经创建的协程。 fatalCompletion仅在拦截机器抛出异常时使用
internal fun Continuation<Unit>.startCoroutineCancellable(fatalCompletion: Continuation<*>) =
    runSafely(fatalCompletion) {
        intercepted().resumeCancellableWith(Result.success(Unit))
    }

接下来调用

@InternalCoroutinesApi
public fun <T> Continuation<T>.resumeCancellableWith(
    result: Result<T>,
    onCancellation: ((cause: Throwable) -> Unit)? = null
): Unit = when (this) {
    is DispatchedContinuation -> resumeCancellableWith(result, onCancellation)
    else -> resumeWith(result)
}

3.1 resumeCancellableWith

 // We inline it to save an entry on the stack in cases where it shows (unconfined dispatcher)
    // It is used only in Continuation<T>.resumeCancellableWith
    @Suppress("NOTHING_TO_INLINE")
    inline fun resumeCancellableWith(
        result: Result<T>,
        noinline onCancellation: ((cause: Throwable) -> Unit)?
    ) {
        val state = result.toState(onCancellation)
        if (dispatcher.isDispatchNeeded(context)) {
            _state = state
            resumeMode = MODE_CANCELLABLE
            dispatcher.dispatch(context, this)
        } else {
            executeUnconfined(state, MODE_CANCELLABLE) {
                if (!resumeCancelled(state)) {
                    resumeUndispatchedWith(result)
                }
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/github_37610197/article/details/125574873