进程与线程
一、并发系统的第一性原理
1. 并发的本质是什么?
并发不是为了更快,而是为了更好地使用有限资源。
在任何计算系统中,都存在三种不可回避的约束:
- **计算资源有限**(CPU 核心、内存、I/O)
- **任务数量不确定**(用户请求、系统服务、后台作业)
- **任务执行时间不可预测**(I/O、外部事件、中断)
因此,并发系统的本质目标是:
在有限资源条件下,对多个任务的时间、状态与共享资源进行有序管理。
这直接引出并发系统必须回答的三个根本问题:
- **执行单元是什么?**(谁在“跑”)
- **如何分配 CPU?**(谁先跑、跑多久)
- **如何安全协作?**(如何共享而不出错)
后续所有概念,都是这三个问题的不同解法。
二、执行单元的抽象演进:进程 · 线程 · 协程
2.1 执行单元的设计哲学
执行单元的演进,本质是三种诉求之间的权衡:
- **隔离性**(安全、稳定)
- **并发性**(吞吐、响应)
- **调度控制权**(灵活性、成本)
2.2 进程:资源隔离的基本单位
进程不是“正在运行的程序”,而是:
一个拥有独立资源视图的执行容器。
原理层定义
- 拥有独立的地址空间
- 拥有完整的资源描述(内存、文件、信号)
- 是操作系统进行**资源分配与保护**的基本单位
设计动机
- 防止错误扩散(一个进程崩溃不影响其他进程)
- 建立清晰的安全与权限边界
代价
- 创建与切换成本高
- 进程间通信复杂
进程解决的是“安全与隔离”问题,而不是“高并发”问题。
2.3 线程:共享资源下的并发执行
线程的引入不是为了节省 CPU,而是为了节省“进程的重复成本”。
原理层定义
线程是共享进程资源的执行流,是调度的基本单位。
核心特征
- 共享地址空间与全局资源
- 拥有独立的栈与寄存器上下文
- 可被内核抢占调度
本质权衡
| 获得 | 付出 |
|---|---|
| 更低创建/切换成本 | 共享状态导致复杂性 |
| 更高并发能力 | 同步与一致性问题 |
线程本质上是:用复杂性换性能。
2.4 协程:调度权下放到用户态
协程的出现不是因为线程“不够快”,而是因为“内核调度太贵、太不可控”。
原理层定义
协程是由程序显式让渡执行权的执行单元。
关键特征
- 切换发生在用户态
- 不依赖内核抢占
- 通常以函数/栈为单位保存上下文
本质优势
- 极低切换成本
- 调度语义可被程序精确控制
本质限制
- 不能自动利用多核
- 阻塞系统调用会阻塞整个调度器(除非运行时接管)
协程的核心价值在于:控制权,而不是并行度。
2.5 执行单元统一对比(原理层)
| 维度 | 进程 | 线程 | 协程 |
|---|---|---|---|
| 抽象层级 | 资源容器 | 执行流 | 调度原语 |
| 资源隔离 | 强 | 无 | 无 |
| 调度者 | 内核 | 内核 | 用户态 |
| 切换成本 | 高 | 中 | 极低 |
| 设计目标 | 安全 | 并发 | 可控 |
三、调度:有限 CPU 的分配艺术
3.1 调度的第一性问题
当多个执行单元同时就绪,而 CPU 有限时,谁先运行?运行多久?
调度的本质是一个资源分配问题,不存在绝对最优解,只有目标权衡。
3.2 调度目标的分类
| 系统类型 | 核心目标 |
|---|---|
| 批处理系统 | 吞吐量、周转时间 |
| 交互式系统 | 响应时间、公平性 |
| 实时系统 | 截止时间、可预测性 |
调度算法的差异,本质是目标函数不同。
3.3 策略与机制分离
机制(Mechanism):
- 上下文切换
- 中断
- 就绪队列
策略(Policy):
- FCFS / SJF / 时间片
- 优先级 / 多级反馈队列
操作系统只负责提供“如何切换”,不决定“该切换给谁”。
这是调度设计中最重要、也最稳定的思想之一。
四、协作与约束:并发正确性的核心
4.1 并发错误的根源
所有并发错误,本质都来自:
多个执行单元,在不可预测的时序下,访问共享状态。
这导致三类问题:
- 竞争条件
- 不一致可见性
- 死锁 / 饥饿
4.2 临界区:共享状态的最小边界
临界区不是代码问题,而是“状态所有权”的问题。
设计原则:
- 同一时刻只允许一个执行单元进入
- 不依赖 CPU 数量与速度假设
- 不阻塞临界区外的执行
- 有限等待
4.3 同步机制的抽象分层
第一层:忙等待(时间换简单)
- 自旋锁
- TSL / CAS
第二层:阻塞同步(让出 CPU)
- 信号量
- 互斥量
- 条件变量
第三层:结构化并发
- 管程
- 屏障
- 读写锁
第四层:避免共享
- 消息传递
- RCU
同步机制的演进趋势:从“控制访问”到“消除共享”。
五、通信模型:共享内存 vs 消息传递
5.1 两种世界观
| 模型 | 核心思想 |
|---|---|
| 共享内存 | 状态共享 + 同步约束 |
| 消息传递 | 状态隔离 + 显式通信 |
两者不是对错,而是复杂性转移的位置不同。
5.2 IPC 机制的层级关系
- 管道 / FIFO:字节流
- 消息队列:结构化通信
- 共享内存:最高性能,最高风险
- 套接字:跨机器边界
六、经典并发问题的统一视角
| 问题 | 本质 |
|---|---|
| 哲学家就餐 | 资源竞争 + 死锁 |
| 读者-写者 | 不同访问语义 |
| 生产者-消费者 | 速率不匹配 |
这些问题的价值不在解法,而在于:
暴露并发系统中不可避免的结构性矛盾。
七、从操作系统到语言运行时
7.1 为什么现代语言要“重造并发模型”?
- 内核线程太重
- 阻塞语义不可控
- 调度策略无法表达业务意图
因此出现:
- Go:Goroutine + M:N 调度
- Java:线程池 + Loom
- Erlang:Actor
并发的未来,不是更快的线程,而是更高层的抽象。
八、总结:稳定知识的沉淀
这套并发体系中,真正长期稳定的不是 API,而是:
- 并发的第一性原理
- 执行单元的权衡逻辑
- 调度的目标函数
- 协作的约束模型
关联内容(自动生成)
- [/操作系统/死锁.html](/操作系统/死锁.html) 死锁是并发系统中进程/线程资源竞争可能导致的问题,与本文档中提到的同步机制和资源管理密切相关
- [/计算机网络/IO模型.html](/计算机网络/IO模型.html) I/O模型涉及进程/线程如何处理I/O操作,与本文档中的执行单元和调度概念紧密相关
- [/编程语言/JAVA/JAVA并发编程/JAVA并发编程.html](/编程语言/JAVA/JAVA并发编程/JAVA并发编程.html) Java并发编程是进程与线程概念的实际应用,展示了如何在编程语言层面实现并发控制
- [/中间件/数据库/数据库系统/事务管理/事务.html](/中间件/数据库/数据库系统/事务管理/事务.html) 数据库事务管理涉及并发控制,与操作系统中的进程/线程同步机制有相似之处
- [/软件工程/架构/系统设计/高并发.html](/软件工程/架构/系统设计/高并发.html) 高并发系统设计需要深入理解进程与线程的工作原理,以实现高效的资源利用和任务调度
- [/操作系统/虚拟化.html](/操作系统/虚拟化.html) 虚拟化技术与进程和线程管理密切相关,涉及资源隔离和调度的高级概念
- [/编程语言/JAVA/JAVA并发编程/线程.html](/编程语言/JAVA/JAVA并发编程/线程.html) Java线程是操作系统线程概念的具体实现,展示了线程在编程语言中的应用
- [/操作系统/linux/Linux性能优化.html](/操作系统/linux/Linux性能优化.html) Linux性能优化涉及进程调度和线程管理,与本文档内容密切相关
- [/计算机网络/运输层.html](/计算机网络/运输层.html) 运输层协议处理进程间通信,与操作系统中的进程概念直接相关
- [/中间件/web中间件/Nginx.html](/中间件/web中间件/Nginx.html) Nginx的并发处理模型与进程和线程的使用方式密切相关