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

为什么多线程的问题本质是“调度”?(从线程到协程 · 第1篇)

系列总纲|第1篇
本系列将从线程 → 线程池 → Reactor → 协程,讲透并发模型的演进本质。


一、先说结论

👉 多线程的问题,不是“线程多”,而是:调度不可控 + 上下文切换成本 + 资源竞争


二、为什么“调度”是核心问题?

很多人理解的调度是:

线程A执行 → 切换到线程B

但这只是表象。


调度的本质 = 三件事

1. 谁来调度(控制权) 2. 怎么调度(策略) 3. 调度带来的副作用(成本)

三、多线程的调度本质(问题从这里开始


1️⃣ 调度权在操作系统(最大问题)

在多线程模型中:

线程调度 = 操作系统决定

👉 这意味着:

  • 什么时候执行?你控制不了
  • 执行多久?你控制不了
  • 什么时候被打断?你控制不了

👉 本质:调度不可控


2️⃣ 抢占式调度(不可预测)

操作系统采用:抢占式调度(Preemptive Scheduling)

👉 结果:

线程A执行中 → 被强制切走 线程B执行 → 线程A何时恢复未知

👉 问题:

  • 执行顺序不确定
  • 逻辑容易被打断
  • 并发问题难以复现

3️⃣ 上下文切换成本(调度的代价)

每一次线程切换,都要做:

保存寄存器 切换栈 进入内核态 恢复另一个线程

👉 这叫:Context Switch(上下文切换)

👉 关键点:一次不贵,频繁发生 → 非常贵


4️⃣ 调度带来的最大问题:资源竞争

因为线程是“并行执行”的:

count++;

在多线程下可能变成:

线程A:读取 count 线程B:读取 count 线程A:+1 写回 线程B:+1 写回(覆盖)

👉 所以必须引入:synchronized / Lock / CAS

结果:

锁竞争 阻塞 死锁 性能下降

四、多线程问题的完整链路(一定要理解)

多线程 ↓ 操作系统调度(不可控) ↓ 抢占执行 + 上下文切换 ↓ 多个线程同时访问共享资源 ↓ 锁 / CAS / 同步机制 ↓ 阻塞 / 死锁 / 性能问题

👉 总结一句:

调度只是起点,资源竞争才是核心痛点


五、那为什么说“调度是本质问题”?

因为:

👉调度决定了所有问题是否发生


举个例子

线程A先执行 → 正常 线程B先执行 → 出问题

👉 这是谁决定的?

调度

👉 所以:调度的不确定性 = 并发问题的根源


六、工程上是怎么解决“调度问题”的?

重点来了(这也是后面系列的主线👇)


1️⃣ 线程池:降低“线程创建成本”

解决:

频繁创建/销毁线程

但没解决:

阻塞 调度不可控 资源竞争

2️⃣ Reactor:减少“无效调度”

核心思想:

不要让线程等 IO

👉 只在“事件就绪”时调度


3️⃣ 协程:改变调度模型(关键突破)

核心思想:

阻塞 → 挂起

👉 原来:

线程等(浪费)

👉 现在:

协程等,线程去干别的

👉 本质:把调度从内核搬到用户态


七、统一模型(这张图要记住)

CPU ↓ 线程(OS调度) ↓ 协程(Runtime调度) ↓ 任务(业务逻辑)

👉 两级调度:

OS 调度线程 Runtime 调度协程

八、一句话讲清所有并发模型

多线程:用更多线程承载更多任务 线程池:减少线程创建成本 Reactor:只在事件就绪时调度 协程:任务挂起,线程不阻塞

九、面试标准回答(可直接背)

多线程的问题本质不是线程本身,而是调度带来的副作用。

在多线程模型下,调度由操作系统控制,是抢占式的,这会导致执行不可控,同时带来频繁的上下文切换和共享资源竞争问题,比如锁竞争、死锁和阻塞。

工程上一般通过线程池减少线程创建成本,通过 Reactor 模型减少无效调度,通过协程把阻塞转换为挂起,从而降低调度成本并提升线程利用率。


十、结尾

👉 到这里你会发现:

线程池只是解决了“线程创建成本”,并没有解决“调度问题”。


下一篇:

《线程池解决了什么?为什么还不够?》

http://www.jsqmd.com/news/731375/

相关文章:

  • YoloX训练实战:从零开始用PyTorch训练一个自定义数据集(附完整代码)
  • 如何3步轻松下载B站大会员4K视频:你的个人高清资源库搭建指南
  • 还在为科研插图烦恼?这个免费图标库让你3分钟搞定专业图表!
  • 从Drupal后台到Root权限:手把手复现DC-8靶场的Exim 4.89提权漏洞
  • 如何快速配置NBFC-Linux:笔记本电脑风扇控制终极指南
  • APP半小时人流量统计基本开发成功
  • 智能开发副驾驶Pilot:用自然语言驱动开发工作流
  • 从零搭建一个CLI工具:手把手教你用Node.js process.argv解析用户输入
  • 文本到视频生成技术:RAPO++框架解析与应用实践
  • 别再手动标注了!用QGIS 3.28导入CSV数据,5分钟搞定地图可视化
  • 爬虫党必看:实测6个免费代理网站,手把手教你筛选出最快最稳的IP
  • 3分钟掌握抖音无水印下载:小白也能用的高清视频保存神器
  • 通过Nodejs快速构建一个集成多模型的后端AI服务
  • 自动化测试新思路:捕获Web应用运行时数据流,构建稳定测试套件
  • ComfyUI ControlNet预处理器完全指南:从零开始掌握AI图像精准控制
  • 告别参考杂散:深入浅出图解小数分频PLL中的Delta-Sigma调制器(附MASH结构对比)
  • 避开FANUC机器人后台编程的坑:DO状态输出程序组掩码设置与常见错误
  • 通过OpenClaw CLI子命令快速写入Taotoken配置对接Agent工作流
  • 别再只盯着PSO和GA了:聊聊GTO等新型元启发式算法的选型与避坑指南
  • 别再只用Task.Run了!用TaskCompletionSource在C#里优雅地控制异步流程(附真实支付场景代码)
  • Windows Cleaner:终极免费的Windows系统清理工具,一键解决C盘爆满问题
  • 在 Node.js 服务中集成 Taotoken 实现稳定 AI 功能调用
  • app权限设计基本完成
  • 3步掌握Adobe全系软件激活:Adobe-GenP实战指南
  • 避坑指南:在银河麒麟V10桌面版安装Qt 5.12.10时,如何解决权限卡死和图标不见的问题?
  • ok-ww:基于图像识别的鸣潮游戏自动化实战指南与深度解析
  • 分离式千斤顶打不上压力怎么回事 - GrowthUME
  • LLM驱动的PACEvolve框架:进化算法新突破
  • Python+GeoPandas实战:5分钟搞定地图坐标系转换(附常见CRS避坑指南)
  • Zephyr驱动初始化顺序详解:你的驱动为什么没跑起来?从链接脚本到启动流程的深度排错