欢迎光临散文网 会员登陆 & 注册

Kotlin Coroutine PARTII:How Dispatcher Works

2022-04-28 18:10 作者:房顶上的铝皮水塔  | 我要投稿

我之前也在b站上发过很多关于Kotlin协程源码分析的专栏,之前发的那些也挺好,但是我目前通过更加全面的学习系统从更加高的一个视角来诠释我对协程之中有意思的点的理解。

第一部分大家可以参考我之前发的这期期视频:

Kotlin协程PartI

主要讲了协程的一些基础内容,然后分析了suspend函数通过转换成自动机而实现的【挂起-恢复】的流程。

之后我也会基于这篇内容发出视频,但是视频的内容尽量压缩到10分钟以内。压缩的目的并不是为了减少知识的量或者是深度,而是将问题局限在一个点,让更大群体的听众能够获取知识和信息。

以下是本篇专栏的目录:

  1. 简单说一下launch的执行逻辑

  2. 任务是如何被分发给Dispatcher执行的

Launch的执行逻辑

在Kotlin中的协程构建器,这里仅举launch为例,它的执行流程满足如下的调用关系:

这个逻辑比较长,中间的部分我不想做过多展开,我们可以看看一头一尾的逻辑:

当我们执行launch方法时,Kotlin编译器会对我们传入的block进行处理。上一期视频中说过这个问题,Kotlin编译器只认suspend关键字,我们传入的block在我们没有注意到的情况下,其实是一个suspend lambda:

Kotlin编译器会进行处理,将这个block(suspend lambda)转换成Continuation,具体大家可以去反编译看一下代码。

我们指直接转到launch的快接近末尾的流程从startCoroutineCancellable开始看:

这个函数会调用下面的三个关联的非常密切的函数,下面简称为【三段式】,也就是图中标颜色的部分:

如下图,【三段式】中的第一个将Kotlin编译器转换的block进行调用,产生Continuation对象;接着,这个Continuation对象调用其扩展方法intercepted,通过ContinuationImpl#intercepted从当前的CoroutineContext中找到ContinuationDisapatcher,并且返回一个DispatchedContinuation:

最后再通过resume方法执行回调函数

任务是如何被分发给Dispatcher执行的?

Dispatcher的设置

通过分析launch的执行流程,可以看到当前的关键就在intercepted过程中。这个过程会找当前的CoroutineContext中的Interceptor。

在Kotlin coroutine库中,Dispatcher,比如我们常见的Dispatchers.Main Dispatchers.IO都是CoroutineInterceptor的子类。在不指定Dispatcher的默认情况下,使用的是Default。这是在launch方法中通过newContext指定的:

Dispatcher分发任务

继续跟踪Dispatchers.Default的intercept流程,就会指引我们走向CoroutineDispatcher#interceptContinuation方法,这也是为什么我上面说会返回 DispatchedContinuation


所以在【三段式】的最后的resumeCancellableWith我们就可以看DispatchContinuation中的定义:

在Dispatchers.Default中的dispatch逻辑是这样干的:

如下图所示,DispatchedContinuation本身是一个Runnable

在dispatch方法中,针对这个runnable进行处理,处理为task之后,通过currentWorker提交到的一个叫做WorkerQueue的队列中:

WorkerQueue本身和Worker是绑定的,关于什么之后执行DispatchContinuation需要看Worker的处理。

以上的逻辑归结到这张图里:

Dispatch Worker#run

这里有必要总结一下,在launch中最先传入的block,通过Kotlin编译器变成了Continuation,通过Interceptor变成了DispatchedContinuation,然后变成了Task,在不同的阶段我们最开始传入的block被不断的包装,名字也随之变化,大家不要弄混了。

Worker#run

Worker#run方法被委托给了runWorker,具体的操作就是不断执行寻找task的操作。

executeTask会执行Task的run方法:

在这里就会检查当前job的状态,并且执行对应的逻辑。


总结

综合来看,Dispatcher分发逻辑是非常清晰的,在最开始执行的时候会调用Kotlin编译器的编译结果,这里没展示,如果出视频的话我会给大家看看,然后会调用最关键的【三段式】,这其实就是对block的一层层的包装处理,在三段式的最后一段调用resume,这样被包装的block就可以放到Dispatcher中去执行了。

Dispatcher具体的逻辑我没有研究,如果之后有机会可以出一期和Java的线程池对比的视频,好!本期专栏就是这样~


Kotlin Coroutine PARTII:How Dispatcher Works的评论 (共 条)

分享到微博请遵守国家法律