抽丝剥茧聊Kotlin协程之协程启动原理

简介: 抽丝剥茧聊Kotlin协程之协程启动原理

1. 前言



本文主要介绍协程的启动原理,如果没有协程实战经验或者没有Debug过协程的源码,看起来可能会有点费劲,但是如果将来有机会学习协程的源码,那么这篇文章可能会对你有一定的帮助。文章主要是讲解协程启动的流程,简便起见,该过程中涉及到的其它比较重要协程知识点可能只会简单提到,本文不会深入去讲解,后续有空会对他们单独成文。


2. 简单的例子



首先 我们来看一个简单的例子,在主线程中开启一个协程,打印“Hello Coroutines”。通过这个简单的例子讲解协程是如何启动起来的。


image.png

接着我们将startCoroutines方法反编译成Java文件


image.png

我们看到Kotlin代码中的Lambda表达式变成了Java中的Function2对象,而它对应的具体类是SuspendLambda。 我们注意到它实现了三个方法:


  1. Object invokeSuspend(Object var1)
  2. Continuation create(Object value,Continuation completion)
  3. Object invoke(Object var1,Object var2)


image.png

image.png

image.png

大家仔细看就会发现,invokeSuspend和create方法定义在BaseContinuationImpl中,invoke方法定义Function2中。而SuspendLambda继承了ContinuationImpl同时又实现了SuspendFunction接口。


在Kotlin中,方法也是对象,一个参数的方法对应的类是Function1,以此类推两个参数方法对应的是Function2。

行文至此,有很多新东西,suspend、Continuation、CoroutineScope、CoroutineContext,但是本文不会讲解,接着往下看协程启动过程吧。


3. 启动过程


3.1 CoroutineScope.launch


image.png

该方法功能如下:


  1. 为新协程创建一个新的CoroutineContext
  2. 本文Case创建StandaloneCoroutine
  3. 调用coroutine.start方法启动协程

image.png

该方法功能如下:


  1. 调用initParentJob方法,与父Job建立关联,当调用cancel方法或者子Job有异常时,可以将取消或者异常事件往上传播(本文暂且忽略,简单了解就好了
  2. 调用start(block, receiver, this),该方法超级有迷惑性,它真正调用的是CoroutineStart的invoke方法。


3.2 CoroutineStart.invoke


image.png

本案例中执行DEFAULT分支


3.3 (suspend(R)->T).startCoroutineCancellable

image.png



最终是通过suspend方法的startCoroutineCancellable方法来启动协程的,本文对应的是lambda,前文我们讲过它对应的是SuspendLambda


{
  println("Hello Coroutines")
}


该方法包含了几个重要方法的调用:


  1. (suspend R.()->T).createCoroutineUnintercepted
  2. Continuation.intercepted()
  3. Continuation.resumeCancellableWith


3.4 (suspend R.() -> T).createCoroutineUnintercepted


image.png

当前的this是启动协程的闭包,前面我们通过反编译startCoroutines方法,发现闭包实现了create方法,此处调用的正是反编译后生成的create方法


image.png参数completion对应的是协程StandaloneCoroutine,此处生成的Function2对象也是SuspendLambda对象


3.5 Continuation.intercepted()


image.png

该方法的主要作用就是生成DispatchedContinuation。它由CoroutineDispatcher和Continuation两部分组成。Dispatcher决定在Continuation在哪个线程中执行,本文是在主线程


3.6 Continuation.resumeCancellableWith


image.png

3.7 MainScope

image.png

image.png

Dispatchers.Main 最终由

kotlinx.coroutines.android.AndroidDispatcherFactory创建


3.8 AndroidDispatcherFactory

image.png

最终通过Handler.post方法把DispatchedContinuation放入主线程消息队列


3.9 DispatchedTask.run


Android主线程调度,最终会调用到DispatchedTask.run方法中,通过continuation.resume方法执行协程体。


image.png


3.10 BaseContinuationImpl.resumeWith


ContinuationImpl.kt

image.png

该方法循环调用Continuation的invokeSuspend方法,直到当前completion是协程本身会跳出循环。


真正执行打印“Hello Coroutines”


image.png

3.11 AbstractCoroutine.resumeWith


协程执行完成

image.png

表示协程执行结束,它可能需要等待子协程结束,结束后需要告知父协程


4. 总结



协程的前置知识点太多了,一篇文章无法解释清楚,有疑问可以在评论区提出。本文主要是讲解了Dispatchers.Main启动协程的过程。Dispatchers.Default启动协程的过程与它又完全不同。

相关文章
|
2月前
|
Java 编译器 测试技术
Kotlin31 协程如何与 Java 进行混编?
Kotlin31 协程如何与 Java 进行混编?
37 2
Kotlin31 协程如何与 Java 进行混编?
|
2月前
|
存储 安全 测试技术
GoLang协程Goroutiney原理与GMP模型详解
本文详细介绍了Go语言中的Goroutine及其背后的GMP模型。Goroutine是Go语言中的一种轻量级线程,由Go运行时管理,支持高效的并发编程。文章讲解了Goroutine的创建、调度、上下文切换和栈管理等核心机制,并通过示例代码展示了如何使用Goroutine。GMP模型(Goroutine、Processor、Machine)是Go运行时调度Goroutine的基础,通过合理的调度策略,实现了高并发和高性能的程序执行。
184 29
|
2月前
|
负载均衡 算法 Go
GoLang协程Goroutiney原理与GMP模型详解
【11月更文挑战第4天】Goroutine 是 Go 语言中的轻量级线程,由 Go 运行时管理,创建和销毁开销小,适合高并发场景。其调度采用非抢占式和协作式多任务处理结合的方式。GMP 模型包括 G(Goroutine)、M(系统线程)和 P(逻辑处理器),通过工作窃取算法实现负载均衡,确保高效利用系统资源。
|
3月前
|
JSON 调度 数据库
Android面试之5个Kotlin深度面试题:协程、密封类和高阶函数
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点。文章详细解析了Kotlin中的协程、扩展函数、高阶函数、密封类及`inline`和`reified`关键字在Android开发中的应用,帮助读者更好地理解和使用这些特性。
51 1
|
4月前
|
调度 Python
揭秘Python并发编程核心:深入理解协程与异步函数的工作原理
在Python异步编程领域,协程与异步函数成为处理并发任务的关键工具。协程(微线程)比操作系统线程更轻量级,通过`async def`定义并在遇到`await`表达式时暂停执行。异步函数利用`await`实现任务间的切换。事件循环作为异步编程的核心,负责调度任务;`asyncio`库提供了事件循环的管理。Future对象则优雅地处理异步结果。掌握这些概念,可使代码更高效、简洁且易于维护。
44 1
|
3月前
|
Java 调度 Android开发
Android面试题之Kotlin中async 和 await实现并发的原理和面试总结
本文首发于公众号“AntDream”,详细解析了Kotlin协程中`async`与`await`的原理及其非阻塞特性,并提供了相关面试题及答案。协程作为轻量级线程,由Kotlin运行时库管理,`async`用于启动协程并返回`Deferred`对象,`await`则用于等待该对象完成并获取结果。文章还探讨了协程与传统线程的区别,并展示了如何取消协程任务及正确释放资源。
59 0
|
3月前
|
数据采集 调度 Python
Python编程异步爬虫——协程的基本原理(一)
Python编程异步爬虫——协程的基本原理(一)
28 0
|
3月前
|
数据采集 Python
Python编程异步爬虫——协程的基本原理(二)
Python编程异步爬虫——协程的基本原理(二)
30 0
|
3月前
|
存储 前端开发 rax
协程设计与原理(二)
协程设计与原理(二)
24 0
|
3月前
|
Java Linux Go
协程的设计原理(一)
协程的设计原理(一)
49 0