Appearance
第 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)算斐波那契 → 全站假死:前台被占满
练习
- 用两句话区分并发与并行。
- 举一个你工作里见过的「两个人改同一份东西」事故,对应竞态还是死锁?
小结
- 共享要协调:锁、原子、队列、通道
- Node 偏事件循环;Go 偏大量轻量协同
- 死锁 = 循环等待;预防靠顺序与超时
附录 A:命令速查;附录 B:自测与进阶。