协程基础夯实以及思考

协程的基础设施层工具

  • 包都是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,协程体才会挂起和恢复。注意两个概念:

  • 协程体相对于当前线程会挂起和恢复
  • 协程体在协程调度器中按照顺序执行,并在执行完后回到挂起点进行恢复
上一篇:bootstarp布局


下一篇:协程