kotlin coroutine start source code analysis

reference article

concept:

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实例。按照惯例,它们 都等待其块内的所有协程完成后  再完成自己,从而 强制执行结构化并发。

Regular code starts the coroutine

        CoroutineScope(Dispatchers.IO).launch {
        
         }

Attach kotlin bytecode decomplie code

      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);
      

The implementation of launch to start kotlin source code is as follows:

参数:
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 extension function 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. The context passed in by the launch method will be combined with the context in CoroutineScope
2. If there is no interceptor in the combined, a default interceptor will be passed in, namely Dispatchers.Default, which also explains why we did not pass in interception There will be a default thread switching effect when the

2. Create Continuation

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

By default, we will create a StandloneCoroutine.
It is worth noting that this coroutine is actually the complete of our coroutine body, that is, the callback after success, not the coroutine body itself. Then
call coroutine.start, which indicates that the coroutine has started.

3. Coroutine start

 coroutine.start(start, coroutine, block)

In fact, the call is

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

Next call

@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)
                }
            }
        }
    }

Guess you like

Origin blog.csdn.net/github_37610197/article/details/125574873