微信直接转wordpress长春网络推广长春seo公司
web/
2025/9/28 6:17:10/
文章来源:
微信直接转wordpress,长春网络推广长春seo公司,手机网站管理系统,phpwind能做网站吗你能听懂的Kotlin协程课#xff0c;跟老司机学#xff0c;不用自己瞎折腾
认识协程
协程难在哪儿?
Ja v a中不曾出现的#xff0c;新概念概念不清晰#xff0c;我们看到的大都是不同语言对于协程的实现或者衍生Kotlin 基础不扎实多线程编程基础太薄弱
协程是什么?
协…你能听懂的Kotlin协程课跟老司机学不用自己瞎折腾
认识协程
协程难在哪儿?
Ja v a中不曾出现的新概念概念不清晰我们看到的大都是不同语言对于协程的实现或者衍生Kotlin 基础不扎实多线程编程基础太薄弱
协程是什么?
协程基于线程它是轻量级线程。
在An dr oid 中协程用来解决什么问题?
处理耗时任务这种任务常常会阻塞主线程。保 证 主线 程 安 全 即 确 保 安 全 地 从 主线 程 调 用 任 何 s u s p e n d 函 数 。
异 步任 务 使用协程 协程是什么?
协程让异步逻辑同步化杜绝回调地狱。协程最核心的点就是函数或者一段程序能够被挂起稍后再在挂起的位 置恢复。
协 程的挂起与恢复
常规函数基础操作包括:invoke (或call)和return协程新增了suspend和resume: • suspend—也称为挂起或暂停用于暂停执行当前协程并保存所有局部变量; • resume—用于让已暂停的协程从其暂停处继续执行。
堆栈帧中的函数调用流程 挂起函数
使用suspen d关键字修饰的函数叫作挂起函数。挂起函数只能在协程体内或其他挂起函数内调用。
调度器 协程的两部分
Kotlin的协程实现分为两个层次: • 基础设施层标准库的协程API主要对协程提供了概念和语义上最基本的支持 • 业务框架层协程的上层框架支
任 务泄 漏
当某个协程任务丢失无法追踪会导致内存、CPU、磁盘等资源浪费甚至发 送一个无用的网络请求这种情况称为任务泄漏。为了能够避免协程泄漏Kotlin引入了结构化并发机制。
结构化并发
使用结构化并发可以做到: • 取消任务当某项任务不再需要时取消它。 • 追踪任务当任务正在执行是追踪它。 • 发出错误信号当协程失败时发出错误信号表明有错误发生
CoroutineScope
定义协程必须指定其CoroutineScope它会跟踪所有协程同样它还可以取消 由它所启动的所有协程。常用的相关API有: • Globalscope生命周期是pr ocess级别的即使Activity或Fragment已经被销毁协程仍然在执行。 • MainSc ope在Activity中使用可以在onDestroy(中取消协程。 • viewModelScope只能在ViewModel中使用绑定ViewModel的生命周期。 • lifecycleScope只能在Activity、Fragment中使用会绑定Activity和Fragment的生命周期。
启动协程
协 程构 建 器
launch与async构建器都用来启动新协程 • launch返回一个Job并且不附带任何结果值。 • async返回一个Deferred, Deferred也是一个Job可以使用.await(在一个延期的值 上得到它的最终结果。等待一个作业 • joinSawait • 组合并发
协 程的启动 模式 DEFAULT:协程创建后立即开始调度在调度前如果协程被取消其将直接进入取消 响应的状态。 ATOMIC:协程创建后立即开始调度协程执行到第一个挂起点之前不响应取消。 LAZY:只有协程被需要时包括主动调用协程的start、join或者await等函数时才会开始 调度如果调度前就被取消那么该协程将直接进入异常结束状态。 UNDISPATCHED:协程创建后立即在当前函数调用栈中执行直到遇到第一个真正挂起 的点 协 程的作用域构建器
coroutineScope-SrunBlocking • runBlocking是常规函数而coroutineScope是挂起函数。 • 它们都会等待其协程体以及所有子协程结束主要区别在于runBlocking方法会阻塞当 前 线 程 来 等 待 而 c o r o u t i n e S c o p e 只 是 挂 起 会释 放 底 层 线 程 用 于其 他 用 途 。
协 程的作用域构建器
coroutineScope-supervisorScope • coroutineScope:一个协程失败了所有其他兄弟协程也会被取消。 • supervisorScope:一个协程失败了不会影响其他兄弟协程。
J ob对象 对 于 每 一 个 创 建 的 协 程 (通 过 l a u n c h 或 者 a s y n c ) 会 返 回 一 个 J o b 实 例 该 实 例 是 协 程 的唯一标示并且负责管理协程的生命周期。 一个任务可以包含一系列状态:新创建(New)、活跃(Active)、完成中(Completi ng)、已完成 (Completed)、取消中 (Cancelling)和已取消 (Cancelled)。虽然 我们无法直接访问这些状态但是我们可以访问J o b 的属性:i s Ac t i v e 、i s Ca n ce l l e d 和i s Completed. J ob的生命周期 如 果 协 程 处 于活 跃 状 态 协 程 运 行 出 错 或 者 调 用 j o b . c a n c e l ()都 会 将 当 前 任 务 置 为 取 消 中 (C a n c e l l i n g ) 状 态 (i s A c t i v e f a l s e , i s C a n c e l l e d t r u e )。 当 所 有 的 子 协 程 都 完 成 后 协 程 会 进 入 已 取 消 (Cancelled)状态此时isCompleted true。 取消协程
协程的取消 取消作用域会取消它的子协程。 被取消的子协程并不会影响其余兄弟协程。 协程通过抛出一个特殊的异常Cancell ationException 来处理取消操作。 所 有 k o t l i n x . c o r o u t i n e s 中 的 挂 起 函 数 (w i t h C o n t e x t 、 d e l a y 等 ) 都 是 可 取 消 的 。 C P U密集型任务取消 isActive是一个可以被使用在CoroutineScope中的扩展属性检查Job是否处于活跃状态。 ensureActive()如果job处于非活跃状态这个方法会立即抛出异常。 yield函数会检查所在协程的状态如果已经取消则抛出Cancellati onExcepti on予以响 应。此外它还会尝试出让线程的执行权给其他协程提供执行机会。 协程取消的副作用 在 f i n a l l y 中释 放 资 源 。 use函数:该函数只能被实现了Closeable的对象使用程序结束的时候会自动调用close 方法适合文件对象。 不能取消的任务 处于取消中状态的协程不能够挂起(运行不能取消的代码)当协程被取消后需要调用挂起函数我们需要将清理任务的代码放置于NonCancellableCoroutineContext 中。 这样会挂起运行中的代码并保持协程的取消中状态直到任务处理完成。 超时任务 很多情况下取消一个协程的理由是它有可能超时。 with Time out OrNull 通过返回null来进行超时操作从而替代抛出一个异常。 协程的上下文
协程的上下文是什么? CoroutineContext是 一组用于定义协程行为的元素。它由如下几项构成: • Jo b:控制协程的生命周期 • Cor outineDis patc her:向合适的线程分发任务 • CoroutineName:协程的名称调试的时候很有用 • CoroutineExceptionHandler:处理未被捕捉的异常 组 合 上下文中的元素 有时我们需要在协程上下文中定义多个元素。我们可以使用操作符来实现。比如说我 们可以显式指定 一个调度器来启动协程并且同时显式指定一个命名 协程 上下文的继承 对于新创建的协程它的Cor outineContext会包含一个全新的Job实例它会帮助我们 控制协程的生命周期。而剩 下的元素会从Corout ine Cont ext的父类继承该父类可能是另外一个协程或者创建该协程的CoroutineSc ope。 协程 上下文的继承
最终的父级Cor outineCont ext 会内含Dispatchers.IO而不是scope对象里的Disp atchers.Mai n因为 它被 协 程 的 构 建 器 里 的 参 数 覆 盖了。 此 外 注 意 一 下父 级 C o r o u t i n e C o n t e x t 里 的 J o b 是 s c o p e 对 象的Job (红色)而新的Job实例(绿色)会赋值给新的协程的CoroutineContext。 协程的异常处理
异常处理的必要性 当应用出现一些意外情况时给用户提供合适的体验非常重要一方面目睹应 用崩溃是个很糟糕的体验另一方面在用户操作失败时也必须要能给出正确 的提示信息。 异常的传播 协程构建器有两种形式:自动传播异常 (launch与actor)向用户暴露异常 (async与produce)当这些构建器用于创建 一个根协程时 (该协程不是另 一个协程 的子协程)前者这类构建器异常会在它发生的第一时间被抛出而后者则依 赖用户来最终消费异常例如通过await或receive 。 非根协程的异常 其他协程所创建的协程中产生的异常总是会被传播。 异常的传播特性 当一个协程由于一个异常而运行失败时它会传播这个异常并传递给它的父级。接下来 父级会进行下面几步操作: • 取消它自己的子级 • 取消它自己 • 将异常传播并传递给它的父级 SupervisorJob 使用Su pervisorJob时一个子协程的运行失败不会影响到其他子协程。Supervis or Job 不会传播异常给它的父级它会让子协程自己处理异常。 这种需求常见于在作用域内定义作业的UI组件如果任何一个UI的子作业执行失 败了它并不总是有必要取消整个UI组件但是如果UI组件被销毁了由于它的 结果不再被需要了它就有必要使所有的子作业执行失败。 supervisorScope 当作业自身执行失败的时候所有子作业将会被全部取消。 异常的捕获 使用Cor outineEx cepti onHandler对协程的异常进行捕获。 以下的条件被满足时异常就会被捕获: • 时机:异常是被自动抛出异常的协程所抛出的(使用launch而不是async时); • 位置:在CoroutineScope的CoroutineContext中或在一个根协程(CoroutineScope 或者supervisorSc ope 的直接子协程)中。 A n d r oi d 中全局 异常处理 全局异常处理器可以获取到所有协程未处理的未捕获异常不过它并不能对异常进行捕获 虽然不能阻止程序崩溃全局异常处理器在程序调试和异常上报等场景中仍然有非常大的 用处。 我们需要在Classpath 下面创建META-INF/services目录并在其中创建一个名为kotlinx. coroutines.Cor outineExceptionHandler的文件文件内容就是我们的全局异常处理器 的全类名。 取消与异常 取 消 与 异常 紧 密 相 关 协 程 内 部 使 用 C a n c e l l a t i o n E x c e p t i o n 来进 行 取 消 这 个异 常 会被 忽略。 当子协程被取消时不会取消它的父协程。 如 果 一 个 协 程 遇 到 了C a n c e l l a t i o n E x c e p t i o n 以 外 的 异 常 它 将 使 用 该 异 常 取 消 它 的 父 协程。当父协程的所有子协程都结束后异常才会被父协程处理。 常聚合 当协程的多个子协程因为异常而失败时一般情况下取第一个异常进行处理。在 第一个异常之后发生的所有其他异常都将被绑定到第一个异常之上。 认识Flow
如何表示多个值? 挂起函数可以异步的返回单个值但是该如何异步返回多个计算好的值呢? 异步返回多个值的方案 集合 序列 挂起函数 Flow Fl ow 与其他方式的区别 名为fl ow的Fl ow类型构建器函数。 f l o w {. . }构 建 块 中 的 代 码 可 以 挂 起 。 函数si mpl eFlow不再标有susp end修饰符。 流使用emit 函数发射值。 流使用col l ec t 函数收集值。 Fl o w 应用 在Androi d当中文件下载是Fl ow的一个非常典型的应用。 冷流 Fl ow是一种类似于序列的冷流fl ow构建器中的代码直到流被收集的时候才运行。 流 的连 续 性 流的每次单独收集都是按顺序执行的除非使用特殊操作符。 从上游到下游每个过渡操作符都会处理每个发射出的值然后再交给末端操作符。 流 构建 器 flowOf构建器定义了一个发射固定值集的流。 使用.asFl ow()扩展函数可以将各种集合与序列转换为流。 上下文 流的收集总是在调用协程的上下文中发生流的该属性称为上下文保存。 f l o w {. . }构 建 器 中 的 代 码 必 须 遵 循 上 下 文 保 存 属 性 并 且 不 允 许 从 其 他 上 下 文 中 发 射 (emit)。 flowOn操作符该函数用于更改流发射的上下文。 启动流 使用launchl n替換collect 我们可以在单独的协程中启动流的收集 流的取消 流采用与协程同样的协作取消。像往常一样流的收集可以是当流在一个可取消的挂起函数 (例如delay)中挂起的时候取消。 流的取消检测 为方便起见流构建器对每个发射值执行附加的ensureActive 检测以进行取消这 意 味 着 从 f l o w {… } 发 出 的 繁 忙 循 环 是 可 以 取 消 的 。 出于性能原因大多数其他流操作不会自行执行其他取消检测在协程处于繁忙循环的情况下必须明确检测是否取消。 通 过 c a n c e l l a b l e 操 作 符 来执 行 此 操 作 。 背压 buffer(并发运行流中发射元素的代码。 c o n f l a t e () 合 并 发 射 项 不 对 每 个 值 进 行 处 理 。 collectLate st()取消并重新发射最后一个值。 当必须更改Cor outineDispatcher时flowOn操作符使用了相同的缓冲机制但 是buffer函数显式地请求缓冲而不改变执行上下文。 操作符
过 渡流 操 作 符 可以使用操作符转换流就像使用集合与序列一样。 过渡操作符应用于上游流并返回下游流。 这些操作符也是冷操作符就像流一样。这类操作符本身不是挂起函数。 它运行的速度很快返回新的转换流的定义。 末端流操作符 末端操作符是在流上用于启动流收集的挂起函数。collect是最基础的未端操作符但是 还有另外 一些更方便使用的末端操作符: • 转化为各种集合例如t oList 与t oSet 。 • 获取第一个(first)值与确保流发射单个(single)值的操作符。 • 使 用 r e d u c e 与 f o l d 将 流 规 约 到 单 个值 。 组合多个流 就像Kotlin标准库中的Sequen ce.zip扩展函数一样流拥有一个zip操作符用于组 合两个流中的相关值。 展平流 流表示异步接收的值序列所以很容易遇到这样的情况 :每个值都会触发对另一 个值序列的请求然而由于流具有异步的性质因此需要不同的展平模式为此存在一系列的流展平操作符: • flatMapConcat连接模式 • flatMapMerge 合并模式 • flatMapLatest 最新展平模式 异常
流的异常处理 当运算符中的发射器或代码抛出异常时有几种处理异常的方法: • try/catcht • catch函数 流的完成 当流收集完成时 (普通情况或异常情况)它可能需要执行一个动作。 • 命令式finally块 • onCompletion声明式处理 Channel-通道
认识Chann el Channel实际上是一个并发安全的队列它可以用来连接协程实现不同协程的 通信。 Channel的容量 Channel实际上就是一个队列队列中一定存在缓冲区那么一旦这个缓冲区满了并且 也 一 直没 有 人 调 用 r e c e i v e 并 取 走 函 数 s e n d 就 需 要 挂 起 。 故 意 让 接 收 端 的 节奏 放 慢 发 现send总是会挂起直到re ceive之后才会继续往下执行。 迭代Chann el Channel 本身确实像序列所以我们在读取的时候可以直接获取一个Channel 的it erator. produceSactor 构造生产者与消费者的便捷方法。 我们可以通过pr oduce 方法启动一个生产者协程并返回一个Receiv eChann el其他协 程 就 可 以 用 这 个 C h a n n e l 来 接 收 数 据 了。 反 过 来 我 们 可 以 用 a c t o r 启 动 一 个消 费 者 协 程 。 Channel的关闭 pr oduce和actor返回的Channel都会随着对应的协程执行完毕而关闭也正是这样Ch a n n e l 才 被 称 为热 数据 流 。 对于一个Channel如果我们调用了它的close方法它会立即停止接收新元素也就是 说 这 时 它 的 i s C l o s e d F o r S e n d 会 立 即 返 回 t r u e 。 而 由 于C h a n n e l 缓 冲 区 的 存 在 这 时 候 可能还有 一些元素没有被处理完因此要等所有的元素都被读取之后isClosedForReceive 才会 返 回 t r u e 。 Ch annel的生命周期最好由主导方来维护建议由主导的一方实现关闭。 BroadcastChannel 前面提到发送端和接收端在Channel 中存在一对多的情形从数据处理本身来 讲虽然有多个接收端但是同一个元素只会被一个接收端读到。广播则不然 多个接收端不存在互斥行为。 多路复用
什么是多路复用 数据通信系统或计算机网络系统中传输媒体的带宽或容量往往会大于传输单一 信号的需求为了有效地利用通信线路希望一个信道同时传输多路信号这就是 所 谓 的 多 路 复 用 技 术 (M u l t i p l e x i n g )。 复 用 多 个a w a i t 两个API分别从网络和本地缓存获取数据期望哪个先返回就先用哪个做展示。 复用多个Channel 跟await类似会接收到最快的那个channel消息。 SelectClause 我们怎么知道哪些事件可以被select呢?其实所有能够被select的事件都是SelectClauseN类型包括: • Select ClauseO:对应事件没有返回值例如join没有返回值那么onJoin就是SelectClauseN类型。使用时onJ oin的参数是一个无参函数。 • SelectClause1:对应事件有返回值前面的onAWait和onReceive都是此类情况。 • Select Clause2:对应事件有返回值此外还需要一个额外的参数例如Channel.onSend有两个参数第一 个是Channel数据类型的值表示即将发送的值;第二个是发送成功时的回调参数。 如果我们想要确认挂起函数是否支持select只需要查看其是否存在对应的Select Clause N类型可回调即可。 使用Flow实现多路复用 多数情况下我们可以通过构造合适的Fl ow来实现多路复用的效果。 并发安全
不安全的并发访问 我们使用线程在解决并发问题的时候总是会遇到线程安全的问题而Java 平台上 的Kotlin协程实现免不了存在并发调度的情况因此线程安全同样值得留意。 协 程的并发工具 除了我们在线程中常用的解决并发问题的手段之外协程框架也提供了一些并发 安全的工具包括: • Channel:并发安全的消息通道我们已经非常熟悉。 • Mutex:轻量级锁它的lock和unlock从语义上与线程锁比较类似之所以轻量是因为它在获取 不到锁时不会阻塞线程而是挂起等待锁的释放。 • Semaphore:轻量级信号量信号量可以有多个协程在获取到信号量后即可执行并发操作。 当 S e m a p h o r e 的 参 数 为 1 时 效 果 等 价 于M u t e x 。 避免访问外部可变状态 编写函数时要求它不得访问外部状态只能基于参数做运算通过返回值提供运 算结果。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/83176.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!