Kotlin之协程coroutine原理

Dispatchers.Main
Dispatchers.IO
Dispatchers.Default
Dispatchers.Unconfined

IO 和 Default 是用公共线程池。区别是两者对核心线程数,最大线程数的配置不一样。

Default是CPU密集型,核心线程数尽可能等于CPU核数

IO是IO密集型,核心线程数尽可能等于任务数, 最大线程数尽可能等于CPU核数和64的两者最大值。

原理是:

开启:

开启协程,编译器会把协程的作用域(代码块)编译成:SuspendLambda 类,这个类会把当前协程被挂起的点分别定义一个状态,每个挂起点对应的状态不一样。SuspendLambda  这个类,会保存当前执行的状态。这样,协程里面的代码块就分成了很多段,每一段之间有一个状态点。正常情况下,协程会按顺序执行完每一段代码。而每一个协程都对应一个Continuation,这个DispatchedContinuation 本质上是实现了Runnable的实例。最终启动,DispatchedContinuation .resumeWith()会把这个DispatchedContinuation 放进对应的线程去执行,IO和Default就会放在线程池,Main就会放在主线程对应的Handler去执行。

挂起:

当在协程里面调用了比如:withContext()等Api时,开启的新的协程就会把当前协程挂起,就会调用

SuspendLambda 里面的挂起放弃,把状态改成:coroutine_suspended,当协程的状态被改成 coroutine_suspended后,执行的流程就会被return掉,不会继续执行后面的代码。

恢复:

启动的子协程,它持有父协程的引用。当子协程执行完后,会调用父协程的SuspendLambda的 invokeSuspend(),把他状态改成运行状态,父协程就会按照状态对应的代码段位置,执行完余下代码。

Dispatchers.Unconfined

未定义线程,被哪个协程挂起,就会在哪个协程的线程上去执行。

原理,挂起它的协程执行完,会调用DispatchedContinuation.resume()方法,里面有一个逻辑是判断指派的线程是什么,如果是未定义,就会拿出当前协程对应线程的EventLoop,通过ThreadLocal去获取。然后就把Unconfined任务放在这个EventLoop去执行。这样能做到,被哪个线程挂起,就在哪个协程对应的线程上去恢复。

猜你喜欢

转载自blog.csdn.net/Leo_Liang_jie/article/details/122951427