Kotlin协程实现原理概述,靠着这份190页的面试资料
现有如下代码:// 求和// 乘以2// 加2// 打印结果我们来将代码SRP一下(单一职责):// 加法// x乘以2// x加2// 最终的test// 从内层依次调用,最终打印可以看到,我们将原来一坨的方法,抽离成了好几个方法,每个方法干一件事,虽然提高了可读性和可维护性,但是代码复杂了,我们来让它更复杂一点。上述代码是 让内层方法的返回值 作为参数 传递给外层方法,现在我们 把外层方法作为
现有如下代码:
fun test(a: Int, b: Int) {
// 求和
var result = a + b
// 乘以2
result = result shl 1
// 加2
result += 2
// 打印结果
println(result)
}
我们来将代码SRP一下(单一职责):
// 加法
fun sum(a: Int,b: Int) = a + b
// x乘以2
fun double(x: Int) = x shl 1
// x加2
fun add2(x: Int) = x + 2
// 最终的test
fun test(a: Int, b: Int) {
// 从内层依次调用,最终打印
println(add2(double(sum(a,b))))
}
可以看到,我们将原来一坨的方法,抽离成了好几个方法,每个方法干一件事,虽然提高了可读性和可维护性,但是代码复杂了,我们来让它更复杂一点。
上述代码是 让内层方法的返回值 作为参数 传递给外层方法,现在我们 把外层方法作为接口回调 传递给 内层方法:
// 加法,next是加法做完的回调,会传入相加的结果
fun sum(a: Int, b: Int, next: (Int) -> Unit) = a + b
// x乘以2
fun double(x: Int, next: (Int) -> Unit) = x shl 1
// x加2
fun add2(x: Int, next: (Int) -> Unit) = x + 2
// 最终的test
fun test2(a: Int, b: Int) {
// 执行加法
sum(a, b) { sum ->
// 加完执行乘法
double(sum) { double ->
// 乘完就加2
add2(double) { result ->
// 最后打印
println(result)
}
}
}
}
这就是CPS的代码风格:通过接口回调的方式来实现的。
假设: 我们上述的几个方法: sum()/double()/add2()都是挂起函数,那么最终也会编译为CPS风格的回调函数方式,也就是:原来看起来同步的代码,经过编译器的"修改",变成了异步的方法,也就是:CPS化了,这就是kotlin协程的顶层实现逻辑。
现在,让我们来验证一下,我们定义一个suspend函数,反编译看下是否真的CPS化了。
// 定义挂起函数
suspend fun test(id: String): String = “hello”
反编译结果如下:
// 参数添加了一个Continuation参数
public final Object test(@NotNull String id, @NotNull Continuation $completion) {
return “hello”;
}
可以看到,多了个Continuation参数,这是个接口,是在本次函数执行完毕后执行的回调,内容如下:
public interface Continuation {
// 保存上下文(比如变量状态)
public val context: CoroutineContext
// 方法执行结束的回调,参数是个范型,用来传递方法执行的结果
public fun resumeWith(result: Result)
}
好,现在我们知道了suspend函数 是通过添加Continuation来实现的,我们来看个具体的业务:
// 根据id获取token
suspend fun getToken(id: String): String = “token”
// 根据token获取info
suspend fun getInfo(token: String): String = “info”
// 测试
suspend fun test() {
// 先获取token,这是耗时请求
val token = getToken(“123”)
// 再根据token获取info,这也是个耗时请求
val info = getInfo(token)
// 打印
println(info)
}
上述的业务代码很简单,但是前两步都是耗时操作,线程会卡在那里wait吗?显然不会,既然是suspend函数,那么就可以CPS化,等价的CPS代码如下:
// 跟上述相同,传递了Continuation回调
fun getToken(id: String, callback: Continuation): String = “token”
// 跟上述相同,传递了Continuation回调
fun getInfo(token: String, callback: Continuation): String = “info”
// 测试(只写了主线代码)
fun test() {
// 先获取token,传入回调
getToken(“123”, object : Continuation {
override fun resumeWith(result: Result) {
// 用token获取info,传入回调
val token = result.getOrNull()
getInfo(token!!, object : Continuation {
override fun resumeWith(result: Result) {
// 打印结果
val info = result.getOrNull()
println(info)
}
})
}
})
}
上述就是无suspend的CPS风格代码,通过传入接口回调来实现协程的同步代码风格。
接下来我们来反编译suspend风格代码,看下它里面是怎么调度的。
协程的底层实现-状态机
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。






既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
学习分享
在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了
很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘
如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。
2021最新上万页的大厂面试真题

七大模块学习资料:如NDK模块开发、Android框架体系架构…

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。
这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
**第三,**到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。
由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。
**
[外链图片转存中…(img-sM1qZWmD-1711936526043)]
七大模块学习资料:如NDK模块开发、Android框架体系架构…
[外链图片转存中…(img-lDOpKnpR-1711936526043)]
只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。
这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
**第三,**到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。
由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。
更多推荐

所有评论(0)