pdf深入理解kotlin协程_协程初探

更新时间:2023-06-14 10:13:42 阅读: 评论:0

pdf深⼊理解kotlin协程_协程初探
Hello,各位朋友,⼩笨鸟我回来了!
近期学习了Kotlin协程相关的知识,感觉这块技术在项⽬中的可应⽤性很⼤,对项⽬的开发效率和维护成本有较⼤的提升。于是就考虑深⼊研究下相关概念和使⽤⽅式,并引⼊到具体项⽬实践中。
本⽂参考了官⽅资料和⽹上相关博主的⽂章,加上⾃⼰的⼀些认知,编写⽽成,当然我本⼈也是初识协程,疏漏及不准确之处希望不吝指出,⾮常感谢。
协程介绍
协程与线程
⼤家都听说过线程,也都知道协程是类似于线程的东西,可能都会认为协程是新出来的东西,但是其实协程出来的更早,只是没有发展成为主流⽽已。
协程最早诞⽣于1958年,被应⽤于汇编语⾔中(距今已有60多年了),对它的完整定义发表于1963年:协程是⼀种通过代码执⾏的恢复与暂停来实现协作式的多任务的程序组件。⽽与此相⽐,线程的出现则要晚⼀些,伴随着操作系统的出现,线程⼤概在1967年被提出。线程作为由操作系统调度最⼩执⾏组件,主要⽤于实现抢占式的多任务。
那么,看起来协程和线程都是处理多任务的⼯作,那么协作式和抢占式多任务处理有啥区别呢?
协作式多任务:协作式多任务要求每⼀个运⾏中的任务,在合适时机⾃动放弃⾃⼰的运⾏权利,告知操作系统可让下⼀个任务运⾏。这就要求任务之间相互熟悉,才能实现协作。不然⼀个任务出问题就会影响全局。
抢占式多任务:抢占式环境下,操作系统完全决定进程调度⽅案,操作系统可以剥夺耗时长的进程的时间⽚,提供给其它进程。线程就是这种设计理念下的产物,这种设计理念下,系统更稳定更⾼效。
上个世纪七⼋九⼗年代,是计算机疯狂朝着⼩型化和个⼈化的⽅向演进的时代,计算机⾮常依赖操作系统来提供⽤户交互和压榨CPU的最⼤性能,⽽操作系统怎么来压榨计算机性能的呢?靠多线程。操作系统跟随个⼈计算机的普及之后,编程语⾔⾃然也开始依赖操作系统提供的接⼝来驾驭计算机了,线程成了⼏乎所有编程语⾔跳不过的⼀个重要概念,并⼀直延续⾄今。
冰箱排名前十的品牌协程是基于编程语⾔层⾯的⼀种概念,它并没有统⼀定义的接⼝,因此在不同的语⾔中实现后的效果是不同的,这也会对开发者造成极⼤的困扰,不利于它的推⼴。不像线程都是基于操作系统的统⼀接⼝,使⽤体验基本⼀致。因此,协程在时代的潮流中就被线程慢慢拉下了。
所以总结⼀下,协程是基于协作式多任务处理设计理念提出的程序组件,需要任务相互熟悉,这与当时的计算机⾏业发展是不相符的。并且接⼝不明确,使⽤成本⾼,所以没流⾏起来。
为什么要引⼊协程
协程提出的很早,但是直到最近⼏年才在某些语⾔上(如Lua,python,kotlin)等上⼤量应⽤。既然上⾯我们已经说到了抢占式多任务处理才更稳定更⾼效,那么为什么协程的概念⼜被拉出来关注了呢?主要还是因为线程有着它的使⽤痛点:线程之间交互难度⽐较⼤。⽽协程在多任务协作上就如鱼得⽔了,所以越来越受重视了。
我们下⾯还是以kotlin协程coroutines来介绍。⾸先我们还是来看段代码,这也是我们⼀开始想写成的dream code:
val token = fetchToken()        // ⽹络请求val ur = fetchUrData(token)  // ⽹络请求 = ur.name
当然,⽼司机们都知道⽹络请求要是在主线程去请求,就会报NetworkOnMainThreadException。那么为了解决这个问题,我们往往会写成这样,也就是回调式写法
fetchToken { token ->    fetchUrData(token) { ur ->        = ur.name    }}
但是回调式写法⼀向被⼈诟病,缺点有且不仅有:
容易造成“回调地狱”
容易造成内存泄露
链路复杂,阅读和维护成本⾼
相互独⽴的调⽤中组合返回结果⾮常困难
当然,⼤家会说,这个问题好解决了,⼈⽣苦短,我⽤Rxjava。当然,Rxjava也是⼀种很好很强⼤的解决⽅式,前提是你能理解他的设计
理念和那么多的operator,学习成本还是太⾼了。⽽kotlin协程就能很好的解决这些问题,让你写出真正的dream code。
coroutineScope.launch(Dispatchers.Main) {    val token = fetchToken()        // ⽹络请求    val ur = fetchUrData(token)  // ⽹络请求    = ur.name
kotlin协程
上⾯讲到了协程跟线程是不⼀样的设计理念,对于协作式的任务的配合⾮常⾼效。但是kotlin协程到底是个啥?除了写代码更爽还有什么优
势?官⽹上说:「本质上,协程是轻量级的线程」。也给出了推荐我们使⽤的⼏个理由:
1.协程很轻量。我们可以在单个线程上运⾏多个协程,因为协程⽀持暂停,不会使正在运⾏协程的线程阻塞。官⽹⽤了这样⼀个例⼦来说明
协程⽐线程轻量。
2 .内存泄露更少: 协程会指定作⽤域,可以在⼀个作⽤域内执⾏针对所有该作⽤域中的协程的操作。 ⽐如取消,全作⽤域错误处理等。 这
种操作也叫“结构化并发”。
3.内置取消⽀持:取消功能会⾃动通过正在运⾏的协程层次结构传播
4.jetpack集成:许多 Jetpack 库都包含提供全⾯协程⽀持的扩展。某些库还提供⾃⼰的协程作⽤域,可供⽤于结构化并发。
⼯程实践
引⼊
实现协程的库是utines,源码可以在 github 上查看。由于kotlin是⼀门⽀持多平台的语⾔,所以coroutines也是⽀持多平台的,
包括:
Kotlin/JS
Kotlin/Native 包括PC和Android
我们需要使⽤coroutines的android版本。要使⽤协程,Kotlin 的版本必须在1.3以上。
implementation "org.jetbrains.kotlinx:"      // 协程核⼼库implementation "org.jetbrains.kotlinx:"
就这样,我们很简单就能开始使⽤协程了。
使⽤
nick怎么读我们先看⼀个简单⽽⼜完整的使⽤协程的例⼦
fun updateName() {    Log.d(TAG, "a")                                  // 主线程中运⾏    coroutineScope.launch(Dispatchers.Main) {            // 主线程中运⾏        Log.d(TAG,
在这个例⼦中,coroutineScope.launch就创建了⼀个协程,并在协程中进⾏了两次切换到IO线程中进⾏⽹络请求的操作,最终把结果展
⽰了出来。同时我们也会发现,由于协程是不阻塞线程的,所以创建完协程后的操作会继续执⾏,⽽单个协程中的执⾏顺序是固定的从上到
下。并且打印出来的log会是 a d b c
散光原因
协程创建
让我们从最常⽤的创建协程的函数launch来看看协程创建:
1.launchlaunch会创建⼀个不会阻塞当前线程、没有返回结果的Coroutine, 但会返回⼀个Job对象,可以⽤于控制这个Coroutine的执⾏
和取消。
val scope = CoroutineScope(Dispatchers.Main)var job = scope.launch(Dispatchers.Main, CoroutineStart.DEFAULT) {    var content = fetchData()    Log.d("Corout 协程创建需要四样东西:
协程作⽤域 CoroutineScope:通过launch或者async启动⼀个协程需要指定CoroutineScope,当要取消协程的时候只需要调
⽤CoroutineScope.cancel() ,kotlin 会帮我们⾃动取消在这个作⽤域⾥⾯启动的所有协程。不建议⽤GlobalScope(应⽤全局⽣命周
期),建议配合后⾯的viewModelScope使⽤。
上下⽂ CoroutineContext:上下⽂是协程的配置参数,可以指定协程的名称,协程运⾏所在线程,异常处理等等。常⽤的有Dispatchers.Default:线程池,适合CPU密集型
Dispatchers.Main:UI线程
Dispatchers.IO:线程池,适合IO密集型
启动模式 CoroutineStart:协程体的执⾏⽅式,常⽤的有
CoroutineStart.DEFAULT:⽴即执⾏协程体
CoroutineStart.LAZY:只在有需要的情况下执⾏
协程体:是⼀段可以放在协程上去运⾏的代码,就好⽐Thread.run当中的代码
2.asyncasync也是很常⽤的创建协程的⽅式,和launch相似也不堵塞当前线程,会返回⼀个Deffered,常⽤于需要启动异步线程处理并
等待处理结果返回的场景。Deffered.await⽅法只能在协程中调⽤。
coroutineScope.launch(Dispatchers.Main) {    //  async 函数启动新的协程    val avatar: Deferred = as
众志成城造句>双子座幸运色ync { Avatar(ur) }    // 获取⽤户头像    val logo: Defer
3.runBlocking创建新的协程运⾏在当前线程上,所以会堵塞当前线程,直到协程体结束。主要是⽤于启动⼀个协程任务。不建议多⽤。
协程挂起
如何理解协程的挂起?我们可以理解为挂起就是⼀个稍后会被⾃动切回来的线程调度操作。让我们来看看这个例⼦
coroutineScope.launch(Dispatchers.Main) {    val token = fetchToken()        // ⽹络请求    val ur = fetchUrData(token)  // ⽹络请求    = ur.name 我们先介绍两个挂起必需品:
suspend:⽤来标记⽅法是⼀个挂起的⽅法,挂起⽅法只能在协程、或者另外的挂起函数中调⽤。本⾝不执⾏任何挂起操作。
withContext:真正执⾏挂起操作。把闭包中的代码切换到指定的线程中执⾏,并在闭包中的代码执⾏完后,⾃动把线程切回来。
这段代码的运⾏过程图为:
看到这⾥,我们可能就会了解: 1.协程挂起的是withContext的闭包的代码 2.协程从当前线程挂起的意思是,这个协程从正在执⾏它的线程上脱离 3.协程挂起以后,两边后续会怎么样?
原来的线程继续运⾏⾃⼰的⼯作,如果是主线程,则进⾏界⾯刷新等后续⼯作
挂起的协程会在新的线程⾥运⾏完闭包中的代码,然后⾃动切回到挂起前的代码
所以,协程的挂起本质上就是线程的切换。协程就是kotlin官⽅提供给我们的⼀套线程操作的框架。有点类似于线程池。所以我们上⾯看到的官⽅拿100000个线程跟100000个协程作⽐较的例⼦,还是有点耍赖哦。
水果图片素材
与retrofit联动
Retrofit 2.6.0版本内置了对Kotlin Coroutines的⽀持,可以直接进⾏使⽤。在那之下的版本需要新增⼀个adapter。详情参考 Retrofit 2.6.0 ! 更快捷的协程体验 !
升级到2.6.0版本以后,可以这样直接使⽤
@GET("xxx")suspend fun getBaidu(): Respon
然后就可以直接使⽤
suspend fun getBaidu(): Respon {    Baidu()}
与Lifecycle联动
Lifecycle KTX 为每个 Lifecycle 对象定义⼀个 LifecycleScope。在此Scope内启动的协程会在 Lifecycle 被销毁时取消。可以通过utineScope 或 lifecycleOwner.lifecycleScope 属性访问 Lifecycle 的 CoroutineScope。
引⼊
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
使⽤
lifecycleOwner.lifecycleScope.launch {    val name = fetchName()    = name}
与jetpack联动
轻视的反义词
Android官⽅提供了丰富的⽀持coroutines的jetpack扩展库。
1.LiveData
LiveData KTX 可提供⼀个 liveData 构建器函数,该函数可以调⽤ suspend 函数,并将结果作为 Live
Data 对象传送出来。
引⼊
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
使⽤
val ur: LiveData = liveData {    val data = databa.loadUr() // loadUr is a suspend function.    emit(data)}
2.ViewModel
ViewModel KTX 库提供了⼀个 viewModelScope() 函数,可以更轻松地从 ViewModel 启动协程。这个CoroutineScope会绑定⾄Dispatchers.Main,并且会在清除 ViewModel 后⾃动取消。
引⼊
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
使⽤
class MainViewModel : ViewModel() {    // Make a network request without blocking the UI thread    private fun makeNetworkRequest() {        // launch a coroutine
3.Room
Room 扩展程序增加了对数据库事务的协程⽀持
引⼊(Room 升级到2.1 版本以上)
implementation ":room-ktx:2.2.5"
使⽤
@Query("SELECT * FROM Urs")suspend fun getUrs(): List
道德与法治手抄报异常处理
上⾯我们说到了⽹络请求和数据库操作等,只要是请求就会有失败的概率,在协程⾥⾯有两种处理⽅式。
1.单协程处理

本文发布于:2023-06-14 10:13:42,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/951752.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:协程   线程   挂起   需要
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图