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

从进程到协程【深度解析】——必懂的并发编程

作为开发者,我们每天都在和 “并发” 打交道 ——APP 里的网络请求要异步执行、后台下载文件不能阻塞 UI、多任务同时处理要避免卡顿…… 而理解进程、线程、协程的本质及关系,是搞定客户端并发编程的核心基础。尤其是协程,如今已成为 Android(Kotlin)、iOS(Swift 5.5+)、跨平台(Flutter/Dart)开发的标配,掌握它能让你彻底摆脱 “回调地狱”,写出更简洁、高效的代码。

进程和线程

进程:程序运行的 “独立容器”

本质

进程的本质是操作系统分配资源的基本单位,可以理解为 “一个正在运行的程序实例”。每个安装在手机上的 APP,启动后都会被操作系统创建一个独立的进程(也可配置多进程),比如你打开微信,系统会为微信分配内存、CPU 时间片、文件句柄等资源,这些资源完全归微信进程独占,和其他 APP 进程隔离。

核心特性
  • 独立地址空间:不同进程的内存空间相互隔离,一个进程崩溃(比如闪退)不会影响其他进程(除非是系统级进程)。比如微信闪退,不会导致支付宝也关闭。
  • 资源独占性:进程拥有自己的堆、栈、文件描述符等,操作系统通过进程 ID(PID)唯一标识。
  • 进程间通信(IPC)成本高:由于隔离性,进程间交换数据需要借助操作系统提供的特殊机制,客户端开发中常见的有:
    • Android:Binder(四大组件通信核心)、AIDL、ContentProvider;
    • iOS:XPC、Mach 端口、Socket;
    • 通用方式:共享内存、消息队列、Socket。

线程:进程的 “执行单元”,CPU 调度的最小单位

本质

线程本质上是CPU可调度的最小执行单元,隶属于进程,是代码的真正执行者。一个进程至少包含一个线程(主线程 / UI线程)。客户端开发有一个铁律:UI 操作必须在主线程(UI 线程)执行,耗时操作必须在子线程执行。

核心特性
  • 轻量级:线程共享所属进程的所有资源(内存、文件句柄等),创建和销毁的开销远低于进程;
  • 抢占式调度:由操作系统内核调度,CPU 会给每个线程分配时间片,线程在时间片内执行,时间片结束后切换到其他线程(上下文切换);
  • 线程安全问题:多个线程共享进程资源时,若同时操作同一数据,会出现 “竞态条件”(比如两个线程同时修改一个计数变量)、死锁等问题。

线程模型的痛点

  • 上下文切换开销:内核切换线程时需要保存 / 恢复线程状态,高并发下开销显著
  • 资源限制:手机端能创建的线程数有限(一般几千级),过多线程会导致调度效率下降;使用线程执行大量IO也会“撑爆线程池”
  • 回调地狱:多线程异步操作嵌套时,代码会变得杂乱(比如 “网络请求→解析数据→更新 UI” 的多层回调)
  • 调度不可控:什么时候切换线程由操作系统决定;切换伴随着寄存器、PC、栈的保存 / 恢复,不适合大量轻量任务

协程

协程是一种比线程更轻量的用户态并发模型,官方描述为用户态的轻量级线程,其调度完全在用户态,不需要操作系统切换上下文。

协程的工作原理

协程的魔法在于“挂起”(Suspend)和“恢复”(Resume)。

想象你在煮面(主任务),同时想烧水(IO任务):

传统同步阻塞:打开水壶 -> 傻站在旁边等水开(CPU 空转) -> 水开了 -> 去煮面。

多线程:雇两个人,一个人盯着水壶,一个人煮面(资源浪费)。

协程:

  • 你去打开水壶(发起 IO)。

  • 你对自己说:“水烧开需要时间,我先去切葱花(挂起当前烧水任务,切换到切葱花任务)。”

  • 水壶响了(IO 完成)。

  • 你放下手里的葱花,回来处理开水(恢复烧水任务上下文)

内部实现原理(简化版)

在代码层面,通常包含一个调度器 (Event Loop)

  1. 协程 A 执行,遇到await(IO 操作)。

  2. 协程 A 将控制权yield(让出)给调度器,并告诉调度器:“等这个 IO 好了叫我”。

  3. 调度器查看任务队列,发现协程 B 可以运行,于是切换到 B 执行。

  4. 当 IO 完成,操作系统通知调度器。

  5. 调度器在合适的时机将协程 A 放回执行队列,从上次暂停的地方继续执行。

协程中的关键概念

协程上下文(CoroutineContext)

协程上下文是协程的运行环境配置,本质是一组元素的集合,定义了协程的运行规则。

核心元素:

  • Job:协程的唯一标识,用于控制协程的生命周期(启动、取消、等待);
  • CoroutineDispatcher:调度器,决定协程运行在哪个线程;
  • CoroutineExceptionHandler:异常处理器;
  • CoroutineName:协程名称,用于调试;
  • ThreadContextElement:线程上下文元素(如日志 MDC、事务上下文)。
协程作用域(CoroutineScope)

协程作用域是协程的生命周期边界,本质 = CoroutineContext + Job,是启动协程的容器,负责定义协程的生命周期、管理作用域内所有协程的层级关系、提供launch(启动协程) asycn(启动带返回值的协程)等方法。

常用作用域

作用域绑定生命周期适用场景
lifecycleScopeActivity/Fragment页面级协程(如 UI 交互、单次请求)
viewModelScopeViewModel数据层协程(如数据缓存、跨页面数据)
GlobalScope应用生命周期不推荐(无结构化并发,易泄漏)
runBlocking阻塞当前线程仅测试场景使用
协程调度器(CoroutineDispatcher)

协程调度器决定协程运行在哪个线程 / 线程池

常用调度器

调度器作用客户端场景
Dispatchers.Main主线程(UI 线程)更新 UI、处理用户交互
Dispatchers.IOIO 密集型线程池网络请求、文件 IO、数据库操作
Dispatchers.DefaultCPU 密集型线程池大数据计算、JSON 解析、图片处理
Dispatchers.Unconfined无指定线程极少使用(易导致线程切换混乱)

线程切换

withContext是协程中最常用的线程切换方法,会挂起当前协程,在指定调度器执行代码后返回结果,自动切回原调度器:

lifecycleScope.launch(Dispatchers.Main) { // 当前在主线程 val data = withContext(Dispatchers.IO) { // 切换到IO线程执行 fetchData() } // 自动切回主线程,更新UI tvContent.text = data }

核心特性

非阻塞:协程通过其特有的挂起机制实现非阻塞,当遇到 I/O操作时(例如网络请求),它会暂停自身执行,将底层的物理线程立即让出给其他可以运行的协程。线程从未阻塞,而是持续工作。

顺序化表达异步逻辑:协程解决了传统异步编程中的”回调地狱“问题,允许开发者使用类似于同步代码的线性、自上而下的风格来编写复杂的异步流程(通过 await 或 suspend 关键字)。

结构化并发:协程的生命周期必须与其所在的程序结构(即协程作用域)绑定,任务不再是独立漂浮的,而是形成了清晰的父子层级关系,有效防止内存泄漏。

协作式取消:协程的取消是协作的,而非抢占的,它不会粗暴地强行终止协程,只有当协程执行到挂起点时,才会检查取消状态。

统一异常处理模型:依赖于结构化并发,异常会沿着Job层级树清晰地向上传播,子协程的未处理异常会传播到父协程,父协程取消时会取消所有子协程;协程内部也可以使用try-catch捕获异常,通过CoroutineExceptionHandler可以捕获作用域内所有未处理的异常。

http://www.cnnetsun.cn/news/5544.html

相关文章:

  • 麒麟操作系统用户和组管理
  • 淀粉下游应用,从餐桌到工业,无处不在!
  • eventpp终极集成指南:5种快速配置C++事件处理库的方法
  • 项目风险管理 论文框架
  • 30+专业幻灯片模板集:轻松打造精美演示文稿
  • 传统中文手写数据集全面解析与应用指南
  • Host侧算子实现总览-解码Ascend C算子的“CPU端蓝图“
  • 科普多种mfc100u.dll丢失的解决方法!全面了解mfc100u.dll文件
  • Wan2.2-T2V-A14B在新闻摘要视频自动生成中的实验成果
  • 31、互联网用户安全防护全解析
  • 技术日报|Kaiju游戏引擎逆袭夺冠,Claude记忆插件日增779星登榜第三
  • 《2025提示工程从入门到进阶指南》正式发布 | 中科算网算泥社区
  • 换了 4 家 AI 模型,代码只动了 1 行——这个架构设计让老板随便折腾
  • 【毕业设计】基于SpringBoot的网上订餐系统设计与实现(基于java网上订餐系统的设计与实现(源码+文档+远程调试,全bao定制等)
  • Python大佬正在用的,但你不知道的几个编程技巧
  • 5步掌握pywebview与React桌面应用开发:终极跨平台解决方案
  • 如何快速获取BDD100K数据集:计算机视觉训练完整指南
  • 【C语言】分支语句(简略版)
  • IP防水等级分为几个等级
  • 2025年国内网络准入系统排行榜,六款超好用的网络准入系统推荐
  • Statuspage开源状态页面终极部署指南:30分钟搭建专业服务监控平台
  • GoldenDict-ng终极配置指南:打造你的专属词典库
  • 5步轻松掌握MinerU:智能文档转换工具完全指南
  • 自动化测试的「千里眼」:当RTSM远程控制遇上自动化,测试效率直接拉满
  • Spring AI 核心架构总览(资深架构师深度解析)
  • 改进YOLOv8结合跨尺度多头自注意力机制实现野火烟雾检测
  • 致进食障碍者
  • 深度合成算法备案超全解析!从定义到落地的4步合规法则
  • 我如何设计一个不会“发疯”的多智能体系统?
  • day122—二分查找—完成旅途的最少时间(LeetCode-2187)