Kotlin 协程完全解读二

我们上一篇文章解释了什么是协程并且稍微解释了一下协程原理,我们本篇文章就来给大家介绍一下Koltin协程里面的一些概念与类

1 CoroutineScope

CoroutineScope 是一个接口,要是查看这个接口的源代码的话就发现这个接口里面只定义了一个属性 CoroutineContext

CoroutineScope可以理解为协程的作用域,每个 coroutine builder 都是 CoroutineScope 的扩展函数,例如lanch,asyn扩展方法 。从这个角度看CoroutineScope 更像是用来创建一个协程的工具类。

一个CoroutineScope可以有许多的子scope。一般情况下每一个CoroutineScope会对应着一个协程,GlobalScope与MainScope等 是例外,他们可以看成是创建协程的入口,本身不对应任何协程。

关于这一块我们放到后面会再行具体解释。

如上的代码最后会形成两个树状结构,左边是CoroutineScope树状结构,右侧是对应的协程树状结构, GlobalScope.launch 方法会创建一个子CoroutineScope 同时创建了这个Scope对应的协程。

在GlobalScope.launch的代码块我们又调用了两次launch创建了子Scope2与子Scope3,注意这里调用的是父Scope的lauch方法。创建这两个Scope的时候也创建了对应的子协程1与子协程2。

从这个树状结构可能更好理解什么是CoroutineScope,每一个CoroutineScope 都是整个树状结构一部分,Scope 就是某一个子树区域。

如果大家还想了解更多关于CoroutineScope 的知识可以参考http://blog.chengyunfeng.com/?p=1086 这篇文章。

CoroutineContext

CoroutineContext翻译成中文就是协程上下文,究其本质CoroutineContext 是一个数据结构,一个类似Map的数据结构,每一个CoroutineScope 内部包含一个CoroutineContext,而CoroutineContext 包含着CoroutineScope 一些信息

例如CoroutineScope 创建的协程运行在哪一个线程池里面,又如CoroutineScope的父CoroutineScope的信息,这些都是保存在CoroutineContext里面。

如下,如果我们调用launch方法创建协程时候没有指定新建的协程运行在哪一个线程池里面,那么默认使用的是CoroutineScope成员变量CoroutineContext 内部保存的Dispatcher,若是CoroutineContext 内部没有Dispatcher那么就会使用默认的Dispatcher.

CoroutineContext  表示的树状结构上的一个节点,内部定义了对这个树的操作,例如get获取元素,plus 添加元素,minusKey 删除元素, 依次对应着Map的 get,add以及remove

CoroutineContext   有两个比较重要的子类Elment以及CombinedContext, Element 对应的叶子节点,而CombinedContext对应的是非叶子节点。换句话说Element此时我们要保存的元素,CombinedContext的作用是构建这个树。

一个典型的CombinedContext 树的结构如下,

其中CoroutineDispatcher是负责协程的分发,决定协程运行在哪一个线程里面。Job就是当前协程的父协程或者是理解成当前CoroutineScope  对应的父CoroutineScope 

Suspend 关键字

suspending functions 就是带有 suspend 关键字的函数。第一 对于用户而言这个关键是是提示用户这个方法只能在 Coroutine 或者其他带有suspend的函数内调用。第二所有被suspend修饰的方法在编译之后都会被动态修改方法的声明,对于没有参数的方法会添加一个Continuation类型的参数,若是存在参数则会参数列表最后添加一个Continuation 类型的参数。无论方法有没有返回值也不论返回值的类型是什么,一律将方法的返回值修改为Object类型。。第三在kotlin 一切皆是对象, kotlin里面方法都可以看成是Function类型的对象,根据参数的个数分为Function1--FunctionN,所有suspend 修饰的方法在编译期间都会创建一个对应的Function2类型的类,这个类就代表这个方法,执行这个方法会创建当前方法对应的协程续体(协程续体也是一个变异期间生成的对应的类),这个协程续体主要的作用就是控制协程的挂起与恢复,也就是控制着状态机状态 。

Continuation 为协程续体,每一个被suspend 修改的方法,都会有一个对应的Continuation ,而且我们上面说了每一个suspend 修饰的方法会多一个Continuation 类型的参数,实际运行过程中就是指的当前suspend 方法在编译期间生成的对应的续体。

testSusoend方法在被编译之后就变成了下面这个样子,testSuspend 本身没有声明任何形式参数,但是编译只有却多出了一个Continuation类型的参数。我们原本也没有声明返回值,编译之后却有了一个Object类型的返回值。

当我们创建协程的时候会传入一个代码块,这个代码块就是一个suspend 方法,在编译期间也会生成一个Funtion2类型的类以及一个Continuation 类型的类。多说一句 这两个类实际是一个类,就像我们创建一个类实现了一个接口继承一个类这里Function2 就是这个被实现的接口,而Continuation 就是被继承的类。

        GlobalScope.launch {
            println("我是一个代码块")
        }

为什么在编译期间会在我们声明的方法形式参数列表内添加一个Continuation 类型的参数以及为什么会添加一个方法返回值。

这跟协程的挂起与恢复密切相关,具体的分析我们放在以后的文章里面。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值