2024年鸿蒙最全Continuation以及实现挂起函数_continuation(1),2024年最新鸿蒙界面用什么语言开发

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

正文

Koltin协程库

其实Kotlin的协程框架代码非常多,但是它有一个层次关系,大致关系图如下:

image.png

我们会发现最下面的叫做协程基础元素,其中就有我们熟悉的CoroutineContext以及Continuation,如果仔细去看里面的代码,会发现它们居然在kotlin标准库中;而中间层则是我们更熟悉的、经常用的一些类,比如Job、Flow,它们是存放在kotlinx.coroutines库中,我们需要单独依赖;这种关系说明了一件什么事情呢

也就是基础元素它更像是砖块而不同的库就是利用这些基础元素封装出的,但是目前还是Kotlin的协程库封装的最好。最后就是因为Kotlin是跨平台实现,所以有特定平台的实现,比如JVM中使用线程池,在JS中使用的是JS线程。

可以发现这个Continuation是基础元素,我们来看看这个基础元素要如何使用。

实现挂起函数

在前面学习中我们知道挂起函数必须由其他挂起函数调用或者协程调用,但是我们一直没有实现一个挂起函数,那下面我们就可以使用suspendCoroutine{}高阶函数来实现一个挂起函数,代码如下:

fun main() = runBlocking {
    println("start")
    val result = getLengthSuspend("Kotlin")
    println(result)
    println("end")
}

suspend fun getLengthSuspend(text: String): Int = suspendCoroutine {
    continuation ->
        thread {
            //模拟耗时
            Thread.sleep(3000)
            continuation.resume(text.length)
        }
}


这里我们定义的挂起函数getLengthSuspend在其内部没有调用其他挂起函数,但是也不会提醒suspend关键字是多余的,说明它就是一个挂起函数,上面代码执行结果如下:

image.png

这里最最无法理解的就是以continuation.resume这样异步的方式传出结果以后,挂起函数就能接收到结果呢?

这里就要结合上一篇文章所说的挂起函数原理了,runBlocking启动的协程,也可以看成一个挂起函数,然后会有一个continuation传递给getLengthSuspend()函数,而当getLengthSuspend中的线程执行完后调用resume方法,又会触发runBlocking的挂起函数中的invokeSuspend方法,从而继续执行后面的操作。

所以这里没有什么神奇的地方,结合前一篇文章的CPS和状态机以及continuation传递就非常好理解,其中continuation.resume会触发调用点函数的continuation的invokeSuspend方法进入下一个状态机状态

suspendCoroutine{}函数

当然这里实现挂起函数的重点是suspendCoroutine{}函数,除了这个还有一个函数是suspendCancellableCoroutine{}函数,这2个高阶函数也是Kotlin协程库的基础元素

我们直接看一下suspendCoroutine函数的定义:

public suspend inline fun <T> suspendCoroutine(crossinline block: (Continuation<T>) -> Unit): T {
    contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
    return suspendCoroutineUninterceptedOrReturn { c: Continuation<T> ->
        val safe = SafeContinuation(c.intercepted())
        block(safe)
        safe.getOrThrow()
    }
}


可以发现这里block函数的参数就是一个continuation,这个continuation就是从其他挂起函数传递进来的。而这里就是Continuation的第一个功能,它可以创建挂起函数,同时把挂起函数的值往外面传递(resume方法)

这里代码其实还是比较容易阅读,除了suspendCoroutineUninterceptedOrReturn外,我们来看一下,它的参数也是一个continuation,我们可知:

  • SafeContinuation就是把原来的Continuation给包裹了一遍
  • 把safe传递给block执行,也就是相当于调用lambda中的逻辑
  • safe.getOrThrow()就是取出block(safe)的运行结果。

那这个suspendCoroutineUninterceptedOrReturn函数是啥呢,直接看源码如下:

public suspend inline fun <T> suspendCoroutineUninterceptedOrReturn(crossinline block: (Continuation<T>) -> Any?): T {
    contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
    throw NotImplementedError("Implementation of suspendCoroutineUninterceptedOrReturn is intrinsic")
}


实际上这里理解这句话的关键是"intrinsic",这里其实指的是编译器领域的一个术语,叫做"内建",即这个函数是由Kotlin编译器来实现的

这里就不探究Kotlin编译器当中的逻辑了,但是我们可以写个demo来看一下这个内建函数的功能与作用。

我们发现这个suspendCoroutineUninterceptedOrReturn的函数类型是(Continuation< T >) -> Any?,这个是不是特别熟悉,它就是上篇文章所说的CPS后的函数的函数类型,而这里的Any?就可以直接返回这个挂起函数是否真的挂起。

比如下面代码:

fun main() = runBlocking {
    val result = testNoSuspendCoroutine()
    println(result)
}

private suspend fun testNoSuspendCoroutine() = suspendCoroutineUninterceptedOrReturn<String> {
        continuation ->
    return@suspendCoroutineUninterceptedOrReturn "Hello!"
}



这里的代码中没有调用continuation.resume(),而是直接返回"Hello",所以它不是真正的挂起函数,将上面方法进行反编译后:

    private static final Object testNoSuspendCoroutine(Continuation $completion) {
      int var2 = false;
      if ("Hello!" == IntrinsicsKt.getCOROUTINE_SUSPENDED()) {
         DebugProbesKt.probeCoroutineSuspended($completion);
      }
    
      return "Hello!";
    }


也可以发现这并不是一个真正的挂起函数。

这时我们写一个真正的挂起函数:

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

的技术提升。**

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 25
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值