协程-执行过程

一、前言

在前面已经了解了协程的使用方法,为了能够更深入的了解协程的设计原理,那么我们来探究以下底层的实现原理。

二、执行过程分析

我们了解到,协程的创建和执行需要在CoroutineScope中,下面我们借助源码来分析CoroutineScope的执行过程。

2.1 创建CoroutineScope对象

    val scope = CoroutineScope(Job()+Dispatchers.IO)

CoroutineScope的创建很简单,传入一个CoroutineContext。

下面我们看一下CoroutineScope的代码:

/**
 * Creates a [CoroutineScope] that wraps the given coroutine [context].
 *
 * If the given [context] does not contain a [Job] element, then a default `Job()` is created.
 * This way, cancellation or failure of any child coroutine in this scope cancels all the other children,
 * just like inside [coroutineScope] block.
 */
public fun CoroutineScope(context: CoroutineContext): CoroutineScope =
    ContextScope(if (context[Job] != null) context else context + Job())

CoroutineScope返回一个根据我们传入的CoroutineContext进行包装,如果传入的context没有Job,那么会使用默认的Job(),CoroutineScope()函数返回ContextScope,ContextScope的代码比较简单,实现CoroutineScope接口,重写coroutineContext属性,并赋值。

internal class ContextScope(context: CoroutineContext) : CoroutineScope {
    override val coroutineContext: CoroutineContext = context
    // CoroutineScope is used intentionally for user-friendly representation
    override fun toString(): String = "CoroutineScope(coroutineContext=$coroutineContext)"
}

ContextScope的创建过程中,我们看到一个特殊的操作操作符“+”,这个对应的是CoroutineContext中的plus方法

public interface CoroutineContext {

    public operator fun plus(context: CoroutineContext): CoroutineContext =
        if (context === EmptyCoroutineContext) this else // fast path -- avoid lambda creation
            context.fold(this) { acc, element ->
                val removed = acc.minusKey(element.key)
                if (removed === EmptyCoroutineContext) element else {
                    // make sure interceptor is always last in the context (and thus is fast to get when present)
                    val interceptor = removed[ContinuationInterceptor]
                    if (interceptor == null) CombinedContext(removed, element) else {
                        val left = removed.minusKey(ContinuationInterceptor)
                        if (left === EmptyCoroutineContext) CombinedContext(element, interceptor) else
                            CombinedContext(CombinedContext(left, element), interceptor)
                    }
                }
            }
    
}

这里关于plus的具体实现可以参考源码中各个CoroutineContext子类的实现,下面用一张图来表示plus()函数最终的效果:
image

这里有个EmptyCoroutineContext对象,我们也需要了解一下它的实现:

public object EmptyCoroutineContext : CoroutineContext, Serializable {
    private const val serialVersionUID: Long = 0
    private fun readResolve(): Any = EmptyCoroutineContext

    public override fun <E : Element> get(key: Key<E>): E? = null
    public override fun <R> fold(initial: R, operation: (R, Element) -> R): R = initial
    public override fun plus(context: CoroutineContext): CoroutineContext = context
    public override fun minusKey(key: Key<*>): CoroutineContext = this
    public override fun hashCode(): Int = 0
    public override fun toString(): String = "EmptyCoroutineContext"
}

这里的EmptyCoroutineContext定义为了一个单例,实现CoroutineContext中相关的方法。

2.2 scope.launch()的执行过程分析

CoroutineScope创建完成后,需要通过launch函数来执行协程代码,下面分析launch函数的执行过程。

    scope.launch {
        print("this code execute in coroutine")
    }

launch后面的lambda就是我们协程,也是我们业务代码执行的代码块,下面看一下launch()函数

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}

launch()是CoroutineScope的扩展方法,三个参数中,CoroutineContext和CoroutineStart都提供了默认的值,该方法最终返回一个Job。该方法首先通过newCoroutineContext()函数返回一个CoroutineContext,下面看一下newCoroutineContext()函数:

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
}

这个函数没有太多的逻辑,控制debug。CoroutineStart没有指定的情况下,默认的是CoroutineStart.DEFAULT,因此会进入coroutine = StandaloneCoroutine,接下来执行coroutine.start(start, coroutine, block),

    /**
     * Starts this coroutine with the given code [block] and [start] strategy.
     * This function shall be invoked at most once on this coroutine.
     *
     * First, this function initializes parent job from the `parentContext` of this coroutine that was passed to it
     * during construction. Second, it starts the coroutine based on [start] parameter:
     * 
     * * [DEFAULT] uses [startCoroutineCancellable].
     * * [ATOMIC] uses [startCoroutine].
     * * [UNDISPATCHED] uses [startCoroutineUndispatched].
     * * [LAZY] does nothing.
     */
    public fun <R> start(start: CoroutineStart, receiver: R, block: suspend R.() -> T) {
        initParentJob()
        start(block, receiver, this)
    }

接下来进入CoroutineStart的invoke()方法

public enum class CoroutineStart {

    ......
    
    public operator fun <R, T> invoke(block: suspend R.() -> T, receiver: R, completion: Continuation<T>): Unit =
        when (this) {
            DEFAULT -> block.startCoroutineCancellable(receiver, completion)
            ATOMIC -> block.startCoroutine(receiver, completion)
            UNDISPATCHED -> block.startCoroutineUndispatched(receiver, completion)
            LAZY -> Unit // will start lazily
        }

}

在launch()方法中,CoroutineStart默认是DEFAULT,接下来执行startCoroutineCancellable()

internal fun <R, T> (suspend (R) -> T).startCoroutineCancellable(
    receiver: R, completion: Continuation<T>,
    onCancellation: ((cause: Throwable) -> Unit)? = null
) =
    runSafely(completion) {
        createCoroutineUnintercepted(receiver, completion).intercepted().resumeCancellableWith(Result.success(Unit), onCancellation)
    }

private inline fun runSafely(completion: Continuation<*>, block: () -> Unit) {
    try {
        block()
    } catch (e: Throwable) {
        completion.resumeWith(Result.failure(e))
    }
}

最后

协程的内容很多,其中的suspend是很重要的一块,这块的实现逻辑还没有完全搞清楚,后期再来弥补这些内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值