反编译后代码分析1

电子说

1.3w人已加入

描述

@

  • 反编译后代码分析

关于协程的一些理解

❝协程挂起让异步代码可以像同步代码一样调用,但其本质还是同步,即协程体中的代码其实是同步。

❝因为协程也只是对线程池的封装,所以需要了解些线程的一些知识。线程本身已经有的协程也会有,但是协程有的线程不一定有

❝编译器会为每一个挂起函数生成一个匿名内部类,其继承SuspendLabmba类重写其invokeSuspend方法,这个方法里面即为协程体的代码【大致内容请先了解】

❝编译器会对协程体中的挂起函数和普通函数进行切割,切割时进行label的自增来保证之后代码的执行顺序,即协程保证运行顺序的本质。【对比线程:进行PC程序计数器的控制来恢复执行】

❝协程体中会添加一个label字段,标识接下来该运行协程体中的哪行代码【即协程如何知道自己执行到哪步是用这个label完成的】(对比线程:线程存储下一个代码指令是用PC计数器来做的)

❝协程体中的数据,看过之前那篇文章的人应该大致了解挂起函数其实就是匿名内部类,数据是保存在栈帧中的,(对比线程:也是通过栈帧中的局部变量表和操作数栈来存储数据)

❝协程体中碰到挂起函数会直接返回,等待挂起函数通知

❝当我们调用挂起函数时都会传入一个Continuation,挂起函数执行完正常退出或者抛异常退出这个时候外面的协程需要知道这个信息,怎么通知呢?通过Continuation的resumewith方法,这个方法会再次调用invokeSuspend取出label来保证之后执行代码的顺序,即协程自动恢复运行的本质

❝(对比线程:方法正常执行完成之后有两种情况1、正常结束,2.异常退出。其里面的PC计数器保证之后执行的代码顺序,也就是说协程在原本线程之上又加了一层控制)

❝协程体中可以在开启一个协程,也就是协程具有父子关系的本质。在协程伊始的时候会默认给一些默认数据(包括协程体运行在哪个线程即调度器其通过拦截器实现,执行状态检测用到的Job,拦截器等等)这些数据保存在协程的上下文中,

❝当在协程体中又开启了一个协程时,其会获取父协程的上下文进行和自己的合并作为自己的上下文。

【简而言之,和协程本身有关的数据保存在上下文中,和业务有关的代码会放在匿名内部类中。】

基础框架层源码分析

val createCoroutine = suspend {
                //挂起函数代码

            }.createCoroutine(object : Continuation<Unit> {
                override val context: CoroutineContext
                    get() = TODO("Not yet implemented")

                override fun resumeWith(result: Result<Unit>) {
     //可从result中获取返回值或异常
                }
            })

   createCoroutine.resume(Unit)

❝1.编译器会对挂起函数做处理,让他继承SuspendCorunting,重写其invokeSuspend方法,方法体为挂起函数中的代码 2.当手动调用createCoroutine返回值的resume方法的时候,会调用到resumeWith函数,其里面会调用invokeSuspend也就是挂起函数体里面的代码,之后两种情况:3.碰到普通函数直接执行;碰到挂起函数传入Continuation并直接返回一个标识代表其为挂起函数,这个时候协程直接退出,之后挂起函数执行完调用Continuation的resumeWith继续执行方法体代码【通过label确定顺序】 4.在invokeSuepend中可以通过result获取挂起函数执行的结果:异常或者返回值。进行对应处理。

实战分析

class ExampleUnitTest {
    @Test
    fun addition_isCorrect() {
        GlobalScope.launch {
            println("挂起点1开始")
            delay(1000)         //挂起点1
            println("挂起点1结束")
            hello()             //挂起点2
            println("挂起点2结束")
            delay(1000)         //挂起点3
            println("挂起点3结束")
            word()              //挂起点4
        }
    }
    //挂起函数,编译器默认传入Continuation
    suspend fun hello(){
        //再次挂起
        withContext(Dispatchers.IO){
            delay(1000)
            println("hello")
        }
    }
    
    suspend fun word(){
        withContext(Dispatchers.IO){
            delay(1000)
            println("word")
        }
    }
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分