接juejin.cn/editor/draf…, 上文分析了协程创建的过程
本文重点分析协程的启动
分析重点:我们知道LaunchUnderTheHoodKt1表示协程体。那么启动协程,也就是触发invokeSuspend函数,所以只要关注底层如何触发invokeSuspend函数这个重点就可以了,有这个前提才就不至于在源码中迷失。
- startCoroutineCancellable 负责创建协程、封装协程、启动协程
public fun <T> (suspend () -> T).startCoroutineCancellable(completion: Continuation<T>): Unit = runSafely(completion) {
createCoroutineUnintercepted(completion).intercepted().resumeCancellableWith(Result.success(Unit))//1
}
//上面的intercepted触发这里
public actual fun <T> Continuation<T>.intercepted(): Continuation<T> =
(this as? ContinuationImpl)?.intercepted() ?: this
//ContinuationImpl.intercepted() 上面的intercepted触发这里
public fun intercepted(): Continuation<Any?> =
intercepted
?: (context[ContinuationInterceptor]?.interceptContinuation(this) ?: this)
.also { intercepted = it }//2
- 注释1:上文分析得知道,startCoroutineCancellable是协程创建、启动的核心,createCoroutineUnintercepted(completion)是负责协程的创建,返回协程体对象 LaunchUnderTheHoodKt1,它间接继承BaseContinuationImpl对象;intercepted是负责协程的包装;resumeCancellableWith负责协程的启动;
- 注释2:context[ContinuationInterceptor]获取协程的Dispatchers,这里是Dispatchers.Default;
- intercepted包装协程
//CoroutineDispatcher类中
public final override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =
DispatchedContinuation(this, continuation)
- Dispatchers.Default的父类是DispatchedContinuation对象,this是Dispatchers.Default本身,continuation是协程体本身;这里是将Dispatchers跟协程体包装起来;
- 开始启动协程
internal class DispatchedContinuation<in T>(
@JvmField val dispatcher: CoroutineDispatcher,//就是Dispatchers.Default
@JvmField val continuation: Continuation<T>// 就是协程体本身
) : DispatchedTask<T>(MODE_UNINITIALIZED), CoroutineStackFrame, Continuation<T> by continuation {
//省略部分代码
inline fun resumeCancellableWith(
result: Result<T>,
noinline onCancellation: ((cause: Throwable) -> Unit)?
) {
val state = result.toState(onCancellation)
if (dispatcher.isDispatchNeeded(context)) {//1
_state = state
resumeMode = MODE_CANCELLABLE
dispatcher.dispatch(context, this)/2
} else {
//省略部分代码
}
}
//省略部分代码
}
- 注释1:只有Dispatchers.Unconfined isDispatchNeeded才返回false,所以走if分支,这里把this传入,this实现了Runnable接口;
- Dispatchers分发任务
//ExperimentalCoroutineDispatcher类中
override fun dispatch(context: CoroutineContext, block: Runnable): Unit =
coroutineScheduler.dispatch(block)//1
- 注释1:Dispatchers.Default的父类是ExperimentalCoroutineDispatcher,注意第二个参数block,它包含协程体本身;coroutineScheduler才是核心,是CoroutineScheduler类型;
- 调度器分发
internal class CoroutineScheduler(
@JvmField val corePoolSize: Int,
@JvmField val maxPoolSize: Int,
@JvmField val idleWorkerKeepAliveNs: Long = IDLE_WORKER_KEEP_ALIVE_NS,
@JvmField val schedulerName: String = DEFAULT_SCHEDULER_NAME
) : Executor, Closeable {//1
//省略部分代码
fun dispatch(block: Runnable, taskContext: TaskContext = NonBlockingContext, tailDispatch: Boolean = false) {
val task = createTask(block, taskContext)//2
val = currentWorker()//3
val notAdded = currentWorker.submitToLocalQueue(task, tailDispatch)、、4
//省略部分代码
}
}
- 注释1:CoroutineScheduler实现Executor,而且注意看属性corePoolSize、maxPoolSize,是不是看到了线程池的影子;
- 注释2:返回TaskImpl任务,持有协程体block;
- 注释3:获取当前Work,也就是线程,尝试将协程添加到线程的本地队列等待调度;
加入本地队列以后,如何被调度呢?
- 核心在Worker.runWorker
internal inner class Worker private constructor() : Thread() {
//省略部分代码
private fun runWorker() {
var rescanned = false
while (!isTerminated && state != WorkerState.TERMINATED) {
val task = findTask(mayHaveLocalTasks)//1
if (task != null) {
executeTask(task)//2
continue
}
//省略部分代码
}
private fun executeTask(task: Task) {
//省略部分代码
runSafely(task)
//省略部分代码
}
fun runSafely(task: Task) {
task.run()//3
//省略部分代码
}
- 注释1:查找要执行的任务;
- 注释2:调用executeTask执行,最后触发task.run(),Task的实现是TaskImpl;
- 注释3:触发TaskImpl的run方法;
internal class TaskImpl(
@JvmField val block: Runnable,
submissionTime: Long,
taskContext: TaskContext
) : Task(submissionTime, taskContext) {
override fun run() {
try {
block.run()
} finally {
taskContext.afterTask()
}
}
//省略部分代码
- 执行构造TaskImpl对象时,传入的block,它包含持有协程体;
- 从前面的分析得知,block是DispatchedContinuation类型,run方法的实现定义在它的父类DispatchedTask类中
internal abstract class DispatchedTask<in T>(
@JvmField public var resumeMode: Int
) : SchedulerTask() {
//省略部分代码
public final override fun run() {
//省略部分代码
try {
val delegate = delegate as DispatchedContinuation<T>
val continuation = delegate.continuation
withContinuationContext(continuation, delegate.countOrElement) {
//省略部分代码
val job = if (exception == null && resumeMode.isCancellableMode) context[Job] else null
if (job != null && !job.isActive) {
val cause = job.getCancellationException()
cancelCompletedResult(state, cause)
continuation.resumeWithStackTrace(cause)
} else {
if (exception != null) {
continuation.resumeWithException(exception)
} else {
continuation.resume(getSuccessfulResult(state))//3
}
}
}
} catch (e: Throwable) {
//省略部分代码
}
- 判断是否有异常、协程是否存活等,都通过了,最后执行continuation.resume;还记得构建DispatchedContinuation对象时的第二个参数吗?所以这里的continuation是协程体本身;
- 协程体间接继承BaseContinuationImpl,所以会触发BaseContinuationImpl.resumeWith
internal abstract class BaseContinuationImpl(
public val completion: Continuation<Any?>?
) : Continuation<Any?>, CoroutineStackFrame, Serializable {
//省略部分代码
public final override fun resumeWith(result: Result<Any?>) {
//省略部分代码
with(current) {
try {
val outcome = invokeSuspend(param)//1
if (outcome === COROUTINE_SUSPENDED) return
Result.success(outcome)
} catch (exception: Throwable) {
Result.failure(exception)
}
//省略部分代码
}
}
}
- 注释1,最后触发协程体实现的invokeSuspend的方法,欧耶,协程体启动了。
总结
协程的启动也就是LaunchUnderTheHoodKt1 invokeSuspend函数被触发;
以上分析有不对的地方,请指出,互相学习,谢谢哦!