知识卡片

进程与线程的演进链条:每一步解决上一步的遗留问题

结构图卡

内容

操作系统里”进程”“线程”这些概念不是一次性设计出来的,而是沿着一条”发现瓶颈→设计新机制解决→新机制又暴露新瓶颈”的链条逐步演进出来的,理解这条链条能帮助判断为什么某个并发机制会长这个样子。最早的计算机没有操作系统,靠用户手工输入指令、计算机执行,大部分时间计算机都在等人输入,效率很低。批处理操作系统解决了这个问题:预先把指令写成一份”任务”清单交给计算机连续执行,不再需要人工干预,但代价是一次只能执行一个任务,如果某个任务在等待I/O设备读取数据,CPU本该空闲那段时间完全被浪费掉。为了利用这段空闲时间,”进程”被发明出来:每个任务对应一个独立的进程、有自己独立的内存空间,操作系统靠给CPU分时间片的方式在多个进程之间切换,看起来像是多进程并行运行。但多进程天生互不相关,如果两个任务需要协作,只能通过慢吞吞的”A写存储、B读存储”方式交互,于是管道、消息队列、信号量、共享存储这些进程间通信机制被设计出来,解决进程之间没法直接沟通的问题。多进程解决了任务之间并行的问题,但单个进程内部依然只能串行处理——比如一个餐馆管理进程里,排位、点菜、买单这些子任务如果严格串行,某个客人买单卡壳(比如信用卡刷不出来)会拖住后面所有客人的点菜。为了让进程内部的子任务也能并行,”线程”被发明出来:线程是进程内部共享同一份数据的子任务,操作系统调度的最小单位从进程下沉到了线程,进程转而变成资源分配的最小单位;但多个线程共享数据又带来了新问题——数据可能被同时修改而出错,于是互斥锁机制被设计出来保证数据正确性。多进程多线程本质上仍是分时系统、并非真正的时间并行,要做到真正的多任务同时执行,最终要靠让多个CPU同时工作,这就是SMP(对称多处理器,即今天常见的多核处理器)、NUMA、MPP这几种真正硬件级并行方案存在的原因。

结构图

flowchart TB
  A["批处理<br/>解决人工手动操作低效<br/>⚠️I/O等待时CPU空闲被浪费"]
  A --> B["进程<br/>分时片利用CPU空闲时间<br/>⚠️进程间互不相关,无法直接协作"]
  B --> C["进程间通信<br/>管道/消息队列/信号量/共享存储<br/>⚠️单进程内部仍是串行"]
  C --> D["线程<br/>进程内子任务并行,共享数据<br/>⚠️共享数据带来正确性问题"]
  D --> E["互斥锁<br/>保证多线程共享数据的正确性<br/>⚠️多进程多线程本质仍是分时,非真并行"]
  E --> F["多CPU并行<br/>SMP/NUMA/MPP<br/>真正意义上的时间并行"]

参考来源

- 位置:《从零开始学架构》第04讲《复杂度来源:高性能》"单机复杂度"(源文件:_epub-src/OEBPS/text00000.html) - 结论依据:原文依次说明批处理"计算机一次只能执行一个任务……CPU其实是空闲的",进程"用进程来对应一个任务……由操作系统来进行调度",进程间通信"为了解决这个问题,进程间通信的各种方式被设计出来了",线程"人们又发明了线程,线程是进程内部的子任务……为了保证数据的正确性,又发明了互斥锁机制",多CPU并行"让多个 CPU 能够同时执行计算任务,从而实现真正意义上的多任务并行。目前这样的解决方案有 3 种:SMP……NUMA……MPP",直接支撑本卡片结论。 - 原始内容:为了进一步提升性能,人们发明了"进程"……多进程虽然要求每个任务都有独立的内存空间,进程间互不相关,但从用户的角度来看,两个任务之间能够在运行过程中就进行通信,会让任务设计变得更加灵活高效……为了解决这个问题,人们又发明了线程……多进程多线程虽然让多任务并行处理的性能大大提升,但本质上还是分时系统,并不能做到时间上真正的并行。