iBoxHub技术日志

怀念我们的昨天,憧憬我们的明天,珍惜我们的今天

进程与线程

一、并发系统的第一性原理

1. 并发的本质是什么?

并发不是为了更快,而是为了更好地使用有限资源。

在任何计算系统中,都存在三种不可回避的约束:

  1. 计算资源有限(CPU 核心、内存、I/O)
  2. 任务数量不确定(用户请求、系统服务、后台作业)
  3. 任务执行时间不可预测(I/O、外部事件、中断)

因此,并发系统的本质目标是:

在有限资源条件下,对多个任务的时间、状态与共享资源进行有序管理。

这直接引出并发系统必须回答的三个根本问题:

  1. 执行单元是什么?(谁在“跑”)
  2. 如何分配 CPU?(谁先跑、跑多久)
  3. 如何安全协作?(如何共享而不出错)

后续所有概念,都是这三个问题的不同解法。


二、执行单元的抽象演进:进程 · 线程 · 协程

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 临界区:共享状态的最小边界

临界区不是代码问题,而是“状态所有权”的问题。

设计原则:

  1. 同一时刻只允许一个执行单元进入
  2. 不依赖 CPU 数量与速度假设
  3. 不阻塞临界区外的执行
  4. 有限等待

4.3 同步机制的抽象分层

第一层:忙等待(时间换简单)

  • 自旋锁
  • TSL / CAS

第二层:阻塞同步(让出 CPU)

  • 信号量
  • 互斥量
  • 条件变量

第三层:结构化并发

  • 管程
  • 屏障
  • 读写锁

第四层:避免共享

  • 消息传递
  • RCU

同步机制的演进趋势:从“控制访问”到“消除共享”。


五、通信模型:共享内存 vs 消息传递

5.1 两种世界观

模型核心思想
共享内存状态共享 + 同步约束
消息传递状态隔离 + 显式通信

两者不是对错,而是复杂性转移的位置不同


5.2 IPC 机制的层级关系

  • 管道 / FIFO:字节流
  • 消息队列:结构化通信
  • 共享内存:最高性能,最高风险
  • 套接字:跨机器边界

六、经典并发问题的统一视角

问题本质
哲学家就餐资源竞争 + 死锁
读者-写者不同访问语义
生产者-消费者速率不匹配

这些问题的价值不在解法,而在于:

暴露并发系统中不可避免的结构性矛盾。


七、从操作系统到语言运行时

7.1 为什么现代语言要“重造并发模型”?

  • 内核线程太重
  • 阻塞语义不可控
  • 调度策略无法表达业务意图

因此出现:

  • Go:Goroutine + M:N 调度
  • Java:线程池 + Loom
  • Erlang:Actor

并发的未来,不是更快的线程,而是更高层的抽象。


八、总结:稳定知识的沉淀

这套并发体系中,真正长期稳定的不是 API,而是:

  • 并发的第一性原理
  • 执行单元的权衡逻辑
  • 调度的目标函数
  • 协作的约束模型