Skip to content

第 10 课 · 并发入门

多人同时干活:令牌、竞态与死锁(只求听懂,不求写操作系统)。

作者:曹宇春


先记住这个类比

部门里多人共享一张 白板(共享内存)

  • 不加锁:两人同时改数字,都基于旧值写回 → 竞态,结果错
  • 锁 / 令牌:谁拿到 marker 谁改,改完归还
  • 死锁:A 拿着文件等打印机,B 拿着打印机等文件 → 互相等,永远卡住

正式概念(人话版)

并发 vs 并行

并发并行
类比一人快速切换接多通电话多人同时接电话
硬件单核也能「交替」多核才能真同时

M 系列多核 ≈ 真能并行多个线程;语言运行时还可能自己排更多轻量任务。

Node.js:一个超级前台

主线程跑 JavaScript;遇到读文件/等网络,先登记回调,去接别的电话;档案到了再回拨。
适合高并发 I/O;纯 CPU 死算会堵死这个前台——要丢 Worker / 子进程。

Go:海量轻量员工(Goroutine)

开销远小于 OS 线程;由 Go runtime 在少量 OS 线程上排班。
Channel ≈ 专用传送带:传数据、少共享内存硬抢。

原子操作

某些「加一」可做成 一步做完、别人插不进来——比锁更轻,适合简单计数。


在你电脑上看一眼

不必写代码也能观察:

bash
# 线程很多、CPU 不高 → 大量在等;反之则在真算
top -l 1 -n 0 | head -12

开发调试时:UI 卡死常是 主线程/事件循环被堵,未必是整机 CPU 100%。


开发里什么时候用得上

  • 两个请求同时改同一行库存 → 要事务/锁/队列
  • 多 Agent 同写一文件 → 文件系统级「并发事故」
  • Node 里 while(true) 算斐波那契 → 全站假死:前台被占满

练习

  1. 用两句话区分并发与并行。
  2. 举一个你工作里见过的「两个人改同一份东西」事故,对应竞态还是死锁?

小结

  • 共享要协调:锁、原子、队列、通道
  • Node 偏事件循环;Go 偏大量轻量协同
  • 死锁 = 循环等待;预防靠顺序与超时

附录 A:命令速查;附录 B:自测与进阶。

© 曹宇春 · 个人学习整理,欢迎交流