协程的基础设施层工具
- 包都是kotlin.coroutine
- 只有suspend、CoroutineContext、Continuation等概念
import kotlin.coroutines.*
fun main() {
coroutine_basic_facilities()
coroutine_basic_facilities_2()
}
/**
* 使用kotlin.coroutine包下的基础设施工具执行协程
* createCoroutine
*/
fun coroutine_basic_facilities() {
println("******begin basic facilities coroutine createCoroutine********")
//挂起函数可以创建协程体createCoroutine,还可以创建并执行startCoroutine
val continuation : Continuation<Unit> = suspend {
//协程体要执行的内容就是挂起函数的内容
Thread.sleep(1000)
println("suspend function execute at ${Thread.currentThread().name}")
5
}.createCoroutine(object : Continuation<Int> {
//协程体存储协程上下文实际上就是通过coroutineContext保存的
override val context: CoroutineContext = EmptyCoroutineContext
//协程体执行完恢复的回调
override fun resumeWith(result: Result<Int>) {
println("resumeWith after suspend function finish with $result at ${Thread.currentThread().name}")
}
})
//如果调用createCoroutine则需要手动触发协程体的恢复
continuation.resume(Unit)
//由于协程并不会阻塞挂起函数以外的代码执行,而只是在调用协程的线程记录协程执行,并最终在协程体执行完成后,在该线程恢复。
// 如果不让外部线程等待,则主线程推出了,协程恢复的时候协程结果都没法输出
Thread.sleep(2000)
println("******finish basic facilities coroutine********")
}
/**
* 使用kotlin.coroutine包下的基础设施工具执行协程
* startCoroutine
*/
fun coroutine_basic_facilities_2() {
println("******begin basic facilities coroutine startCoroutine********")
//挂起函数可以创建协程体createCoroutine,还可以创建并执行startCoroutine
val continuation = suspend {
//协程体要执行的内容就是挂起函数的内容
Thread.sleep(1000)
println("suspend function execute at ${Thread.currentThread().name}")
5
}.startCoroutine(object : Continuation<Int> {
//协程体存储协程上下文实际上就是通过coroutineContext保存的
override val context: CoroutineContext = EmptyCoroutineContext
//协程体执行完恢复的回调
override fun resumeWith(result: Result<Int>) {
println("resumeWith after suspend function finish with $result at ${Thread.currentThread().name}")
}
})
//由于协程并不会阻塞挂起函数以外的代码执行,而只是在调用协程的线程记录协程执行,并最终在协程体执行完成后,在该线程恢复。
// 如果不让外部线程等待,则主线程推出了,协程恢复的时候协程结果都没法输出
Thread.sleep(2000)
println("******finish basic facilities coroutine********")
}
协程的框架业务层工具
- 包都是kotlinx.coroutine
- 有CoroutineScope、Job已经各种诸如delay的函数
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.system.measureTimeMillis
suspend fun main() {
println("******begin framework facilities coroutine********")
var cost : Long
val firstJob = GlobalScope.launch {
cost = measureTimeMillis {
suspendOne("firstJob")
suspendTwo(6, "firstJob")
}
println("first coroutine cost $cost")
}
val secondJob = GlobalScope.launch {
//注意,这里两个协程不阻塞,很快执行完了,但是协程体会在执行完后又在该上下文中恢复
cost = measureTimeMillis {
GlobalScope.launch {
suspendOne("secondJob")
}
GlobalScope.launch {
suspendTwo(4, "secondJob")
}
}
println("second coroutine cost $cost")
}
println("******sleep framework facilities coroutine********")
firstJob.join()
secondJob.join()
println("******finish framework facilities coroutine ********")
}
suspend fun suspendOne(callName : String) {
delay(1000)
println("$callName suspendOne return 23")
23
}
suspend fun suspendTwo(origin : Int, callName: String) {
delay(2000)
println("$callName suspendOne return ${origin * 2}")
origin * 2
}
协程体
Cotinuation就是协程体,是suspend挂起函数的Receiver。
这也是挂起函数可以调用普通函数,但是普通函数无法直接调用挂起函数的原因。
协程体中的CoroutineContext是保存协程上下文现场的关键,协程恢复现场就是使用了这里的数据。
挂起函数并没有挂起,而是协程体挂起了。
而协程体会在协程调度器中运行,即使是在主线程上运行也如此,如Dispatchers.Main、Dispatchers.IO、Dispatchers.Default
协程挂起点在协程调度器执行完协程后会恢复,然后将协程体挂起点后面的部分(恢复上下文)执行完
挂起函数
挂起函数并不是真的挂起,而是告诉编译器这个函数可能会耗时,而协程体才是挂起函数的Receiver,协程体才会挂起和恢复。注意两个概念:
- 协程体相对于当前线程会挂起和恢复
- 协程体在协程调度器中按照顺序执行,并在执行完后回到挂起点进行恢复