kotlin协程
协程是什么
协程实际上是一个轻量级的线程,可以挂起并稍后恢复
kotlin中,协程把异步编程放入库中来简化这类操作。程序逻辑在协程中顺序表述,而底层的库会将其转换为异步操作。库会将相关的用户代码打包成回调,调度其执行到不同的线程,而代码依然像顺序执行那么简单。
协程的优势
协程主要是让原来要使用“异步+回调”写出来的复杂代码,简化成看起来是同步的代码,本质上是callback的语法糖。
kotlin标准库提供的基本的元素/操作
suspend 关键字
Kotlin在1.1版本新增加了 suspend 关键字,可以用来修饰函数或者 lambda 表达式
1 | suspend fun suspendFun(): String {} |
被suspend修饰的方法只能在另一个suspend方法或者一个协程中被调用,suspend表示这个方法是一个可中断挂起的方法
CoroutineContext
CoroutineContext是协程的上下文,表示一系列用户自定义的Object,也就是代表代码块执行在哪个场景
1 | interface CoroutineContext { |
- get:获取当前指定Key对应的Context
- fold:类似集合的fold方法,用于累加
- plus:重载操作符plus,使得context之间可以用’+’符号运算获得一个新的context
- minusKey:获得除指定Key对应的Context之外的所有Context
Continuation
表示协程中的执行单元
1 | public interface Continuation<in T> { |
ContinuationInterceptor
Continuation的拦截器,继承自CoroutineContext,如果当协程的Context包含ContinuationInterceptor那么当前协程内所有的Continuation在执行前都会经过拦截器的替换。
创建和启动协程
创建协程的方式很简单,我们需要一个suspend lambda和一个Continuation,标准库为suspend lambda定义了扩展方法startCoroutine
1 | public fun <T> (suspend () -> T).startCoroutine( |
该方法创建并启动一个协程,该协程的Context由传入的Continuation提供,且lambda执行完毕后回调该Continuation的resumeWith方法
挂起/恢复协程
通过在一个协程中调用标准库提供的suspendContinue方法来挂起当前协程
1 | public suspend inline fun <T> suspendCoroutine(crossinline block: (Continuation<T>) -> Unit): T = |
该方法接受一个参数为Continuation的lambda,开始执行该lambda并挂起当前协程,如果想要恢复协程的执行,通过调用传入的Continuation的resumeWith方法来恢复
Kotlinx提供的协程库
1 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.1' |
对基础库协程的封装,提供更加简洁的api
1 | GlobalScope.launch(Dispatchers.Main) { |
原理
可挂起的方法采用CPS(Continuation-Passing-Style)实现,每一个可挂起的方法被调用的时候都会被隐式的传递一个Continuation参数来表示后续的操作。
采用Continuation则是一种函数调用方式,它不采用堆栈来保存上下文,而是把这些信息保存在continuation record中。这些continuation record和堆栈的activation record的区别在于,它不采用后入先出的线性方式,所有record被组成一棵树(或者图),从一个函数调用另一个函数就等于给当前节点生成一个子节点,然后把系统寄存器移动到这个子节点。一个函数的退出等于从当前节点退回到父节点。
最大的好处就是,它可以让你从任意一个节点跳到另一个节点。而不必遵循堆栈方式的一层一层的return方式。比如说,在当前的函数内,你只要有一个其它函数的节点信息,完全可以选择return到那个函数,而不是循规蹈矩地返回到自己的调用者。你也可以在一个函数的任何位置储存自己的上下文信息,然后,在以后某个适当的时刻,从其它的任何一个函数里面返回到自己现在的位置。
1 | val a = a() |
ViewModel支持的协程
参考资料
https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md#coroutine-context
https://www.cnblogs.com/cheukyin/p/6444860.html