Suppend

Coroutine API

GlobalScope 在 Dispatchers.Main launch 的过程

GlobalScope.launch(Dispatchers.Main) {
  println("hello word")
}
Log.e(TAG, "-----------------------")

--- source code ---
public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}

从这张流程图中,可以大概熟悉一下,一个简单的协程的的使用过程。

可以了解到:协程体怎么分发到对应的线程中执行:

在这里插入图片描述

这里的CoroutineDispatcher 就是 HandlerDispatch,在Dispatchers.Main执行的都是 通过Handler.post() 执行.

这里特别需要注意,supped.R() -> TSuspendLambda 的子类. 由虚拟机生成,同时复写 invokeSuspendcreateinvoke 方法

withContext 切换线程

GlobalScope.launch(Dispatchers.Main) {
    Log.e(TAG, "run in main thread 1")
    withContext(Dispatchers.IO) {
        Log.e(TAG, "run in io thread")
    }
    Log.e(TAG, "run in main thread 2")
}
Log.e(TAG, "-----------------------")

看代码,会发现线程变化是: Main Thread -> IO Thread -> Main Thread

怎么做到的呢?

在Android中代码先执行到:GlobalScope.launch(Dispatchers.Main),会通过post,执行launch的代码体。

然后改变 Context,设置不同的Dispatchers,将 Log.e(TAG, "run in io thread") 分发到CommonPool 里面执行。

特别需要注意的是:有三个不同的路径来执行

  • context与父级的context相等

  • Dispatchers 与父级的Dispatchers相等

  • 如果是新的Dispatchers,这里会构建DispatchedCoroutine,这个类会持有两个context,一个新的一个是旧的。

    为的就是将线程切换过来(会在afterResume调用)
    在这里插入图片描述

SuspendLambda 继承结构

在这里插入图片描述

状态机

https://kotlinlang.org/spec/asynchronous-programming-with-coroutines.html#coroutine-state-machine

// Lambda body with multiple suspension points
val a = a()
val y = foo(a).await() // suspension point #1
b()
val z = bar(a, y).await() // suspension point #2
c(z)
// State machine code for the lambda after CPS transformation
//     (written in pseudo-Kotlin with gotos)
class <anonymous> private constructor(
    completion: Continuation<Any?>
): SuspendLambda<...>(completion) {
    // The current state of the state machine
    var label = 0
    
    // local variables of the coroutine
    var a: A? = null
    var y: Y? = null
    
    fun invokeSuspend(result: Any?): Any? {
        // state jump table
        if (label == 0) goto L0
        if (label == 1) goto L1
        if (label == 2) goto L2
        else throw IllegalStateException()
        
      L0:
        // result is expected to be `null` at this invocation
        
        a = a()
        label = 1
        // 'this' is passed as a continuation 
        result = foo(a).await(this) 
        // return if await had suspended execution
        if (result == COROUTINE_SUSPENDED)
            return COROUTINE_SUSPENDED
      L1:
        // error handling
        result.throwOnFailure()
        // external code has resumed this coroutine
        // passing the result of .await() 
        y = (Y) result
        b()
        label = 2
        // 'this' is passed as a continuation
        result = bar(a, y).await(this)
        // return if await had suspended execution
        if (result == COROUTINE_SUSPENDED)
            return COROUTINE_SUSPENDED
      L2:
        // error handling
        result.throwOnFailure()
        // external code has resumed this coroutine
        // passing the result of .await()
        Z z = (Z) result
        c(z)
        label = -1 // No more steps are allowed
        return Unit
    }          
    
    fun create(completion: Continuation<Any?>): Continuation<Any?> {
      <anonymous>(completion)
    }          
    
    fun invoke(completion: Continuation<Any?>): Any? {
        create(completion).invokeSuspend(Unit)
    }
}

总结

supped.R() -> TSuspendLambda 的子类. 由虚拟机生成,同时复写 invokeSuspendcreateinvoke 方法

invokeSuspend 是一个状态机的构造,每个挂起点都是一个状态.

withContext 切换线程:在开启新的线程的时候,会将旧的context的封装到:DispatchedCoroutine(newContext, uCont),在afterResume的时候重启.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值