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********") }
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,协程体才会挂起和恢复。注意两个概念: