当前位置: 首页 > article >正文

协程(入门)

Kotlin 协程系统指南从入门到高级实战目标读者Android/Kotlin 开发者阅读目标不仅会“用 API”还要理解协程的设计思想、边界和工程落地方式。目录协程为什么出现先解决了什么问题协程核心概念全景图第一段协程代码逐行讲解suspend 的本质挂起不是阻塞作用域与生命周期结构化并发的入口Dispatcher 与线程切换策略并发组合launch/async/await 正确使用取消与超时可控结束比成功更重要异常传播与 Supervisor 思维模型Flow 入门什么是冷流Cold Flow冷流 vs 热流StateFlow/SharedFlow 全面对比Flow 常见操作符与背压处理Android 架构落地ViewModel RepositoryChannel 与 Actor协程间通信与串行化状态高级主题并发安全、性能优化、调试手段协程测试runTest、虚拟时间与可测性完整业务案例审批页并发加载 重试 超时 事件流常见误区与实践清单可直接贴团队规范1. 协程为什么出现先解决了什么问题1.1 传统线程模型的痛点线程创建和上下文切换成本高回调嵌套callback hell使代码难维护异步任务生命周期难统一管理容易泄漏错误处理分散try-catch 到处写1.2 协程提供的价值用“同步代码风格”表达异步逻辑轻量级并发可创建大量协程结构化并发保证任务生命周期可控配合 Flow/StateFlow 可自然描述 UI 数据流1.3 一个直观类比把“线程”想成“整间会议室”创建和切换都昂贵把“协程”想成“会议中的议程项”挂起时让出时间片成本很低。2. 协程核心概念全景图Coroutine可挂起可恢复的任务单元suspend标记可挂起函数CoroutineScope协程的生命周期容器Job协程句柄取消、状态跟踪Dispatcher运行调度器Main/IO/DefaultCoroutineContext上下文集合Job Dispatcher Name Handler可以先记住一句话协程 任务suspend 生命周期Scope/Job 执行策略Dispatcher3. 第一段协程代码逐行讲解importkotlinx.coroutines.*funmain()runBlocking{println(main start:${Thread.currentThread().name})valjoblaunch{println(child launch)delay(500)println(child done)}println(main waiting)job.join()println(main end)}说明runBlocking桥接普通函数与协程世界阻塞当前线程直到内部完成测试/示例常用launch启动无返回值协程delay挂起不阻塞线程join等待job完成4. suspend 的本质挂起不是阻塞4.1 什么是“挂起”挂起是当前协程暂时停下把线程让给别人等条件满足再恢复。4.2 生活类比你在餐厅点餐后不会一直站在柜台前堵住别人阻塞而是拿号去等挂起叫号再回来继续。4.3 代码示例suspendfunfetchUser():String{delay(300)returnTom}suspendfunloadPage(){valuserfetchUser()println(user$user)}4.4 常见误区suspend不是“自动异步线程切换”suspend函数内部如果做 CPU 重活且不切到Default依旧可能卡主线程5. 作用域与生命周期结构化并发的入口5.1 为什么必须有 Scope没有作用域就像“放飞无人机不设返航”任务何时结束、失败如何收口都不清楚。5.2 结构化并发原则子协程属于父协程父协程结束/取消子协程自动结束避免GlobalScope这种脱离生命周期的“野生协程”5.3 示例coroutineScopesuspendfunloadUserPage(repo:Repo):UserPagecoroutineScope{valprofileasync{repo.getProfile()}valpostsasync{repo.getPosts()}UserPage(profileprofile.await(),postsposts.await())}coroutineScope保证任何子任务失败整体感知并收敛。6. Dispatcher 与线程切换策略6.1 常见 DispatcherDispatchers.MainUI 更新Dispatchers.IO网络、文件、数据库Dispatchers.DefaultCPU 计算6.2 推荐线程策略ViewModel 层在MainRepository 做 IO 切换重计算切到Default6.3 示例suspendfunloadDetail(api:Api):DetailwithContext(Dispatchers.IO){api.getDetail()}suspendfuncalc(items:ListInt):IntwithContext(Dispatchers.Default){items.sum()}7. 并发组合launch/async/await 正确使用7.1 何时用 launch只关心执行不关心返回值如上报日志、触发事件7.2 何时用 async需要结果且可能并发等待多个结果7.3 页面并发加载示例suspendfunloadDashboard(api:Api):DashboardcoroutineScope{valprofileasync{api.profile()}valnoticesasync{api.notices()}valstatsasync{api.stats()}Dashboard(profileprofile.await(),noticesnotices.await(),statsstats.await())}7.4 注意async的异常在await()时抛出不要“创建了 async 却忘记 await”8. 取消与超时可控结束比成功更重要8.1 为什么取消重要App 页面退出、任务过时、用户主动中断都需要及时取消避免浪费资源。8.2 基础取消valjobscope.launch{repeat(10){delay(200)println(work$it)}}job.cancel()8.3 协作式取消CPU 任务scope.launch(Dispatchers.Default){while(isActive){// heavy compute}}8.4 超时valresultwithTimeoutOrNull(1000){api.longTask()}9. 异常传播与 Supervisor 思维模型9.1 默认传播模型在普通coroutineScope中某个子协程失败通常会取消同级。9.2CoroutineExceptionHandler适用范围主要对根launch有效async要在await处处理。9.3 Supervisor局部失败不拖垮全局valscopeCoroutineScope(Dispatchers.MainSupervisorJob())scope.launch{valalaunch{error(A fail)}valblaunch{delay(300);println(B still running)}joinAll(a,b)}适合场景页面多个模块并行加载某个模块失败不影响其他模块展示。10. Flow 入门什么是冷流Cold Flow10.1 定义冷流只有在被收集collect时才开始生产数据每个收集者都会触发一套新的生产过程。10.2 生活类比冷流像“点播视频”你点开才开始播放每个人点开都是自己的播放进度。10.3 示例证明“每次 collect 都重新执行”funtickerFlow()flow{println(flow start)repeat(3){delay(300)emit(it)}}scope.launch{tickerFlow().collect{println(collector A -$it)}}scope.launch{tickerFlow().collect{println(collector B -$it)}}你会看到flow start打印两次因为两次收集是两套独立执行。10.4 适用场景用户操作触发一次网络请求流需要“懒执行”数据处理流水线11. 冷流 vs 热流StateFlow/SharedFlow 全面对比11.1 什么是热流热流不依赖是否有人收集数据源可能一直在产生数据。生活类比热流像“广播电台”电台一直播听众随时加入冷流像“点播节目”你点开才播放11.2 三者定位Flow冷流按需执行StateFlow热流保存并提供“最新状态”SharedFlow热流广播事件可配置缓存/replay11.3 StateFlow 示例状态dataclassUiState(valloading:Booleanfalse,valdata:String?null,valerror:String?null)privateval_uiStateMutableStateFlow(UiState())valuiState:StateFlowUiState_uiStatefunsetLoading(){_uiState.value_uiState.value.copy(loadingtrue)}特点必须有初始值永远有最新值新订阅者会立刻拿到当前值11.4 SharedFlow 示例事件sealedinterfaceUiEvent{dataclassToast(valmessage:String):UiEventdataobjectNavigateBack:UiEvent}privateval_eventsMutableSharedFlowUiEvent(replay0,extraBufferCapacity1)valevents:SharedFlowUiEvent_eventssuspendfunsendToast(msg:String){_events.emit(UiEvent.Toast(msg))}特点适合一次性事件Toast、导航、弹窗可控制 replay/buffer 行为11.5 常见选择规则页面“状态” -StateFlow页面“一次性事件” -SharedFlow计算/请求流水线 -Flow12. Flow 常见操作符与背压处理12.1 常见操作符flowOf(1,2,3,4).map{it*2}.filter{it4}.onEach{println(emit$it)}.catch{e-println(error${e.message})}.collect()12.2 高频输入场景搜索框queryFlow.debounce(300).distinctUntilChanged().flatMapLatest{keyword-repository.search(keyword)}.collect{result-render(result)}解释debounce防抖distinctUntilChanged去重flatMapLatest只保留最新请求旧请求自动取消12.3 背压与处理策略buffer()生产和消费解耦conflate()只保留最新值跳过中间值collectLatest()来新值就取消上一次处理13. Android 架构落地ViewModel Repository13.1 推荐职责分层ViewModel状态与事件编排Repository数据获取与线程切换DataSource/API具体 IO 实现13.2 示例classApproveViewModel(privatevalrepository:ApproveRepository):ViewModel(){privateval_stateMutableStateFlow(ApproveUiState())valstate:StateFlowApproveUiState_stateprivateval_eventsMutableSharedFlowString()valevents:SharedFlowString_eventsfunload(procInsId:String){viewModelScope.launch{_state.update{it.copy(loadingtrue)}runCatching{repository.fetchDetail(procInsId)}.onSuccess{detail-_state.update{it.copy(loadingfalse,detaildetail)}}.onFailure{e-_state.update{it.copy(loadingfalse)}_events.emit(e.message?:加载失败)}}}}classApproveRepository(privatevalapi:ApproveApi){suspendfunfetchDetail(id:String):ApproveDetailwithContext(Dispatchers.IO){api.getDetail(id)}}14. Channel 与 Actor协程间通信与串行化状态14.1 Channel点对点/队列通信valchannelChannelInt(capacityChannel.BUFFERED)scope.launch{repeat(5){channel.send(it)}channel.close()}scope.launch{for(iteminchannel){println(receive$item)}}14.2 Actor把共享状态写入串行化sealedinterfaceCounterMsgobjectInc:CounterMsgclassGet(valreply:CompletableDeferredInt):CounterMsgfunCoroutineScope.counterActor()actorCounterMsg{varcount0for(msginchannel){when(msg){Inc-countisGet-msg.reply.complete(count)}}}适用高并发下避免锁竞争保证单线程顺序更新。15. 高级主题并发安全、性能优化、调试手段15.1 并发安全常见风险多个协程同时修改同一可变对象。解决方案不可变数据结构MutexActor 串行化valmutexMutex()varcounter0suspendfunsafeInc(){mutex.withLock{counter}}15.2 性能优化建议不要把小任务切成过多协程IO/CPU 任务严格分 Dispatcher减少无意义线程切换Flow 高频链路使用buffer/conflate/collectLatest15.3 调试建议JVM 参数开启调试-Dkotlinx.coroutines.debug协程命名CoroutineName(LoadApproveTimeline)关键节点打印currentCoroutineContext()信息16. 协程测试runTest、虚拟时间与可测性推荐依赖kotlinx-coroutines-testOptIn(ExperimentalCoroutinesApi::class)classApproveViewModelTest{Testfunload success updates state()runTest{valvmApproveViewModel(FakeApproveRepository(successtrue))vm.load(proc-1)advanceUntilIdle()assert(vm.state.value.loading.not())assert(vm.state.value.detail!null)}}关键点runTest替代runBlockingadvanceUntilIdle()推进虚拟时间测试中避免真实延迟和真实网络17. 完整业务案例审批页并发加载 重试 超时 事件流场景进入审批详情页并发请求三类数据允许瞬时失败重试总时长受控失败发事件提示。suspendfunloadApprovePage(procInsId:String):ApprovePageDatacoroutineScope{suspendfunTretry(times:Int2,block:suspend()-T):T{varlast:Throwable?nullrepeat(times1){try{returnblock()}catch(e:Throwable){lastedelay(200)}}throwlast?:IllegalStateException(unknown)}valdetailasync{withTimeout(3000){retry{approveApi.getDetail(procInsId)}}}valdictasync{withTimeout(3000){retry{dictApi.getApproveDict()}}}valtimelineasync{withTimeout(3000){retry{approveApi.getTimeline(procInsId)}}}ApprovePageData(detaildetail.await(),dictdict.await(),timelinetimeline.await())}这个例子同时体现结构化并发coroutineScope并发请求async超时withTimeout重试retry错误收敛await抛出18. 常见误区与实践清单可直接贴团队规范18.1 常见误区在业务层使用GlobalScope主线程执行 IO没有取消策略和超时策略把一次性事件塞进StateFlowasync创建后忘记awaitFlow 链路过长但无背压策略18.2 实践清单生命周期归属明确viewModelScope/lifecycleScopeRepository 统一withContext(Dispatchers.IO)状态用StateFlow事件用SharedFlow关键请求设置超时、重试、兜底对高频输入加debounce flatMapLatest测试统一runTest结语协程真正的难点不在 API 数量而在工程思维任务归属谁Scope跑在哪Dispatcher何时停取消/超时失败怎么办异常传播/Supervisor数据如何流动Flow/StateFlow/SharedFlow如果你愿意我下一步可以再给这份文档补两章“协程面试高频题附标准回答”“结合你当前screen/repository/utils目录的项目落地模板可直接复制”

相关文章:

协程(入门)

Kotlin 协程系统指南(从入门到高级实战) 目标读者:Android/Kotlin 开发者 阅读目标:不仅会“用 API”,还要理解协程的设计思想、边界和工程落地方式。 目录 协程为什么出现:先解决了什么问题协程核心概念全…...

多动症治疗方法是什么?主要有哪些运动干预方案?

多动症治疗的全面解析:运动干预影响儿童注意力 多动症是一个常见的儿童行为障碍,其关键特征包括注意力不集中和冲动行为。研究表明,运动干预可以显著改善儿童的 注意力缺陷。通过有目标的运动,例如团队运动和有氧运动,…...

openclaw免费(白嫖/试用)指南(适合新手)

openclaw(龙虾)免费试用指南 前言 openclaw实在是太火了,但咱们小白玩这个龙虾其实有两点不方便。 1、泄密风险 2、token要收费。 对于泄密风险,我的方案是使用云服务器,而不是自己的电脑来安装龙虾。至于收费的问题…...

原生H5如何优雅拦截浏览器返回事件:全面屏侧滑退出的解决方案

1. 为什么需要拦截浏览器返回事件? 最近几年全面屏手机普及率越来越高,很多用户养成了通过侧滑手势返回上一页的操作习惯。这种交互方式确实很方便,但在某些特殊场景下却会给开发者带来困扰。比如图片预览、弹窗展示这类需要用户明确关闭的页…...

2026/3/23(上周速览AI)

上周速览 上周最强的主线,不是“又出了一个新模型”,而是 AI 正在从模型竞争转向三场更大的战争: 第一,中国大厂集体把重心推向智能体(agent)和超级入口,腾讯、百度、阿里、小米都在加码。第二&…...

MemOS\Mem0与OpenClaw的整合安装

要实现MemOS与OpenClaw的整合安装,核心目标是通过MemOS的长效记忆管理解决OpenClaw“记不住、Token消耗高”的痛点,同时支持多OpenClaw实例协作。以下是2026年最新、最详细的分步指南,覆盖环境准备、OpenClaw安装、MemOS插件配置、多实例协作…...

东莞城市学院“华为企业级专家人才培养计划”开班典礼圆满成功!

春风送暖,万象更新。2026年3月19日,东莞城市学院“华为企业级专家人才培养计划”开班典礼隆重举行。人工智能学院执行院长张伟明、企业代表袁泽帆、项目教务班主任欧亚梅老师及全体首期学员共同出席了典礼,正式开启了这段赋能未来的卓越学习之…...

文墨共鸣多场景:法律文书相似性筛查、医疗报告术语一致性验证

文墨共鸣多场景:法律文书相似性筛查、医疗报告术语一致性验证 1. 项目概述 文墨共鸣是一个将深度学习技术与传统美学相结合的语义相似度分析系统。基于阿里达摩院开源的StructBERT大模型,专门针对中文语义理解进行了优化,能够精准识别文字间…...

Z-Image-Turbo企业应用探索:MCN机构批量生成艺人宣传图的自动化流程设计

Z-Image-Turbo企业应用探索:MCN机构批量生成艺人宣传图的自动化流程设计 1. 项目背景与需求分析 在当今内容为王的时代,MCN机构面临着巨大的视觉内容生产压力。每位签约艺人都需要大量的宣传图片用于社交媒体、活动海报、粉丝互动等场景。传统的人工设…...

使用cloudflare解决个人宽带80端口问题

完全不要钱,命名隧道(Named Tunnel)同样是免费的。免费的具体内容多个来源都确认了这一点:项目免费额度命名隧道数量最多 1000 个连接数每个隧道最多 100 个活动连接流量无限制HTTPS 证书自动免费签发域名托管需将域名 DNS 托管在…...

Guohua Diffusion 游戏素材生产流水线:自动化生成角色与场景原画

Guohua Diffusion 游戏素材生产流水线:自动化生成角色与场景原画 如果你在独立游戏开发团队待过,肯定对美术资源的生产周期和成本深有体会。一个角色从概念设计到最终立绘,一个场景从草图到上色完成,动辄数天甚至数周&#xff0c…...

关于PythonGatewayServer未关闭

一、问题描述我已经停止作业,并且关闭了flink和zookeeper服务,jps后显示7645 PythonGatewayServer还存在。二、为什么会出现这种情况?可能是以下情况造成:1.PyFlink 的设计:PythonGatewayServer 是在 JVM 中运行的独立…...

图像压缩新突破:深入解析S2LIC中的全局注意力机制与棋盘上下文模型

图像压缩新突破:深入解析S2LIC中的全局注意力机制与棋盘上下文模型 当你在社交媒体上传照片时,是否曾因文件过大而被迫降低画质?4K视频创作者是否常为存储空间不足而烦恼?这些痛点背后,是传统图像压缩技术已触及性能天…...

SUNFLOWER MATCH LAB 低代码集成:在Dify平台上快速创建植物识别AI应用

SUNFLOWER MATCH LAB 低代码集成:在Dify平台上快速创建植物识别AI应用 你是不是也对那些能识别花草树木的AI应用感到好奇?觉得它们很酷,但又觉得开发起来肯定特别复杂,需要写很多代码,还得懂深度学习?今天…...

WPS格式问题

图注(1)图注标号不是章节号点击“自定义编号设置格式即可插入公式后行距不对...

零代码部署:基于EagleEye DAMO-YOLO TinyNAS的毫秒级目标检测系统搭建

零代码部署:基于EagleEye DAMO-YOLO TinyNAS的毫秒级目标检测系统搭建 1. 目标检测技术的新突破 想象一下这样的场景:工厂质检员需要从数百个监控画面中找出产品缺陷,安保人员要24小时盯着几十路监控视频寻找可疑人员,零售分析师…...

保姆级教程:在Ubuntu 22.04上用gst-rtsp-server搭建你的第一个RTSP视频流服务器

从零搭建RTSP视频流服务器:Ubuntu 22.04与gst-rtsp-server实战指南 流媒体技术正在重塑我们消费视频内容的方式。想象一下,你刚开发了一款智能家居摄像头,或者正在构建一个远程监控系统,如何让这些设备产生的视频流能够被网络上的…...

2026年光模块设备行业深度研究报告:AI驱动需求爆发+CPO迭代的封装测试设备机遇

摘要:本报告分析了光模块设备行业双主线“AI驱动技术迭代”的发展趋势,为行业从业者与投资者提供核心参考。AI算力需求推动光模块向800G/1.6T升级,CPO/OIO技术落地催生封装测试设备新需求,贴片、耦合、测试仪器为核心环节&#xf…...

新手必看:ERNIE-4.5-0.3B镜像开箱即用,5分钟体验AI对话

新手必看:ERNIE-4.5-0.3B镜像开箱即用,5分钟体验AI对话 1. 为什么选择ERNIE-4.5-0.3B镜像 如果你正在寻找一个轻量级但能力强大的中文文本生成模型,ERNIE-4.5-0.3B-PT绝对值得尝试。这个镜像已经帮你解决了所有部署难题: 一键部…...

EcomGPT-中英文-7B电商模型入门教程:3步完成本地开发环境搭建与测试

EcomGPT-中英文-7B电商模型入门教程:3步完成本地开发环境搭建与测试 你是不是对电商AI模型很好奇,想自己动手试试,但又担心环境配置太复杂?别担心,这篇教程就是为你准备的。我们完全从零开始,目标是让你在…...

DOCTYPE(文档类型)的作用是什么?

DOCTYPE&#xff08;Document Type Declaration&#xff0c;文档类型声明&#xff09;是 HTML 文档的第一行代码&#xff08;位于 <html> 标签之前&#xff09;&#xff0c;它的主要作用是告诉浏览器当前文档使用的是哪个 HTML 或 XHTML 版本规范&#xff0c;从而决定浏览…...

AI修复艺术画作可行吗?国画细节还原实战测试报告

AI修复艺术画作可行吗&#xff1f;国画细节还原实战测试报告 1. 开场&#xff1a;一张泛黄的《溪山行旅图》局部&#xff0c;能被AI“救活”吗&#xff1f; 上周整理旧资料时&#xff0c;翻出一张扫描自古籍插页的宋代山水画局部——墨色晕染、线条模糊、分辨率 barely 超过4…...

Arduino Giga Display Shield GT911触摸驱动库详解

1. 项目概述Arduino_GigaDisplayTouch 是专为 Arduino Giga Display Shield 设计的触摸控制器驱动库&#xff0c;采用标准 C 编写&#xff0c;深度适配 Arduino API 生态&#xff0c;面向 STM32H747XI 双核&#xff08;Cortex-M7 Cortex-M4&#xff09;主控平台。该库并非通用…...

计算机毕业设计:Python动漫数据可视化分析系统全栈开发 Flask框架 可视化 爬虫 大数据 机器学习 番剧推荐(建议收藏)✅

博主介绍&#xff1a;✌全网粉丝10W,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业项目实战6年之久&#xff0c;选择我们就是选择放心、选择安心毕业✌ > &#x1f345;想要获取完整文章或者源码&#xff0c;或者代做&#xff0c;拉到文章底部即可与…...

二分查找解题:咒语与药水的成功配对

二分查找class Solution:def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]:ans []n len(potions)potions.sort()for num in spells:left, right 0, len(potions)while left < right:mid (left right) // 2if num * po…...

用 LangBot 把 Dify Agent 接入微信、QQ、飞书,10分钟搞定

在这里插入图片描述 用 LangBot 把 Dify Agent 接入微信、QQ、飞书&#xff0c;10分钟搞定 想让你的 Dify Agent 不只是在网页里跑&#xff0c;而是能直接在微信群、QQ 频道、飞书里回复消息&#xff1f;LangBot 就是为这个场景设计的。本文手把手教你完成这个集成&a…...

大学生论文全流程辅助工具oowzai实测:从开题到答辩的高效解决方案

作为常年和大学生论文打交道、也帮不少同学梳理过论文写作问题的博主&#xff0c;我发现大家写毕业论文、课程论文的时候&#xff0c;难的从来不是单纯凑字数写内容&#xff0c;而是卡在选题框架、文献规范、内容逻辑、格式排版、查重降重这些核心环节&#xff0c;再加上现在高…...

el-upload二次封装带表格校验组件

需求背景&#xff1a;项目里的附件上传以往都是通过调用后端上传附件接口&#xff0c;由后端接口负责校验附件以及表单规则&#xff0c;项目经理现为了优化性能&#xff0c;决定由前端先行校验表格内部分基础规则内容&#xff08;如判断是否为空表格&#xff0c;列表项内容是否…...

ARMv8.1原子操作避坑指南:从LDXR到CAS指令的完整迁移教程

ARMv8.1原子操作迁移实战&#xff1a;从LL/SC到LSE的深度优化 在移动计算和服务器领域&#xff0c;ARM架构正经历着从v8.0到v8.1的关键跃迁。这次升级不仅仅是时钟频率的提升&#xff0c;更带来了处理器原子操作范式的根本性变革——LSE&#xff08;Large System Extension&am…...

告别‘鬼畜’发音:VITS微调中音频数据准备的3个关键步骤与工具推荐

突破VITS语音合成瓶颈&#xff1a;专业级音频预处理全流程指南 当你听到VITS模型合成的语音出现机械感、断句不自然或背景杂音时&#xff0c;问题往往出在最初的数据准备阶段。作为AI语音合成领域的核心技术&#xff0c;VITS对输入音频的质量要求极高&#xff0c;而大多数失败案…...