Day 055 — 进程并发图解
1. 进程 vs 线程架构对比
┌───────────────────────────────────────────────────────────┐
│ 线程模型 (Threading) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ 进程 (Process) │ │
│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │
│ │ │ Thread 1 │ │ Thread 2 │ │ Thread 3 │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ 堆内存 │ │ 堆内存 │ │ 堆内存 │ │ │
│ │ │ (共享) │ │ (共享) │ │ (共享) │ │ │
│ │ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ │ │
│ │ │ │ │ │ │
│ │ └───────────────┼───────────────┘ │ │
│ │ ▼ │ │
│ │ ┌─────────────────┐ │ │
│ │ │ 🔒 GIL (全局锁) │ │ │
│ │ │ 同一时刻只有 │ │ │
│ │ │ 一个线程执行 │ │ │
│ │ └─────────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────┐
│ 进程模型 (Multiprocessing) │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Process 1 │ │ Process 2 │ │ Process 3 │ │
│ │ ┌────────┐ │ │ ┌────────┐ │ │ ┌────────┐ │ │
│ │ │ 🐍 Py │ │ │ │ 🐍 Py │ │ │ │ 🐍 Py │ │ │
│ │ │ 解释器 │ │ │ │ 解释器 │ │ │ │ 解释器 │ │ │
│ │ │ + GIL │ │ │ │ + GIL │ │ │ │ + GIL │ │ │
│ │ └────────┘ │ │ └────────┘ │ │ └────────┘ │ │
│ │ ┌────────┐ │ │ ┌────────┐ │ │ ┌────────┐ │ │
│ │ │ 独立 │ │ │ │ 独立 │ │ │ │ 独立 │ │ │
│ │ │ 内存 │ │ │ │ 内存 │ │ │ │ 内存 │ │ │
│ │ └────────┘ │ │ └────────┘ │ │ └────────┘ │ │
│ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ │
│ │ │ │ │
│ └───────────────┼───────────────┘ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ 📡 IPC 通信 │ │
│ │ Queue/Pipe/ │ │
│ │ SharedMem │ │
│ └─────────────────┘ │
│ │
│ ✅ 各进程 GIL 独立 → 多核并行 │
└───────────────────────────────────────────────────────────┘
2. multiprocessing.Process 生命周期
创建 Process 对象
│
▼
start() ──────────────────────────────────────┐
│ │
▼ ▼
┌──────────┐ ┌──────────────┐
│ 主进程 │ │ 子进程 │
│ 继续执行 │ │ 执行 target │
└────┬─────┘ └──────┬───────┘
│ │
│ join() ───→ 阻塞等待 │ 完成/异常
│ │
▼ ▼
┌──────────┐ ┌──────────────┐
│ 获取 │ │ exitcode: │
│ exitcode │ │ 0 = 正常 │
│ │ │ >0 = 异常 │
└──────────┘ │ <0 = 被终止 │
└──────────────┘
terminate() ──→ 强制终止子进程(发送 SIGTERM)
kill() ──→ 强制杀死子进程(发送 SIGKILL)
3. Queue 内部结构
┌─────────────────────────────────────────────────┐
│ multiprocessing.Queue │
│ │
│ 生产者进程 消费者进程 │
│ │ │ │
│ │ put(item) │ get() │
│ ▼ ▲ │
│ ┌──────────┐ ┌──────┐ ┌──────────┐ │
│ │ Buffer │──▶│ Pipe │──▶│ Buffer │ │
│ │ (feeder) │ │ │ │ (reader) │ │
│ └──────────┘ └──────┘ └──────────┘ │
│ │ │ │
│ └────────┬───────────────────┘ │
│ ▼ │
│ ┌────────────┐ │
│ │ 🔒 Lock │ 线程安全 & 进程安全 │
│ └────────────┘ │
│ │
│ put_nowait() → 队列满抛 Full │
│ get_nowait() → 队列空抛 Empty │
│ qsize()/empty()/full() → 近似值,不可靠 │
└─────────────────────────────────────────────────┘
4. Pool 工作流程
┌──────────────────────────────────────────────────────┐
│ Pool 进程池 │
│ │
│ 主进程 │
│ │ │
│ │ pool = Pool(4) │
│ │ │
│ │ pool.map(func, [1,2,3,4,5,6,7,8]) │
│ │ │ │
│ │ ▼ │
│ │ ┌─────────────────────────────────────────┐ │
│ │ │ 任务分发器 (Task Distributor) │ │
│ │ └──┬────────┬────────┬────────┬──────────┘ │
│ │ │ │ │ │ │
│ │ ▼ ▼ ▼ ▼ │
│ │ ┌──────┐┌──────┐┌──────┐┌──────┐ │
│ │ │W-1 ││W-2 ││W-3 ││W-4 │ │
│ │ │func(1)││func(2)││func(3)││func(4)│ │
│ │ └──┬───┘└──┬───┘└──┬───┘└──┬───┘ │
│ │ │ │ │ │ │
│ │ ▼ ▼ ▼ ▼ │
│ │ ┌─────────────────────────────────────────┐ │
│ │ │ 结果收集器 (Result Collector) │ │
│ │ └────────────────┬────────────────────────┘ │
│ │ │ │
│ │ ▼ │
│ │ 返回 [r1, r2, r3, r4, r5, r6, r7, r8] │
│ │ │
│ └── pool.map() 阻塞直到全部完成 │
└──────────────────────────────────────────────────────┘
5. 进程间通信方式选择
需要进程间通信?
│
▼
┌────────────┐
│ 数据量大小?│
└─────┬──────┘
│
┌────┴────┐
▼ ▼
小数据 大数据
│ │
▼ ▼
┌────────┐ ┌────────────┐
│简单数值│ │复杂对象? │
└───┬────┘ └──────┬─────┘
│ │
▼ ┌────┴────┐
┌────────┐ ▼ ▼
│Value/ │ 是 否
│Array │ │ │
│(共享 │ ▼ ▼
│ 内存) │ ┌──────┐ ┌──────┐
└────────┘ │Queue │ │Pipe │
│(多对 │ │(点对 │
│ 多) │ │ 点) │
└──────┘ └──────┘
│
▼
┌────────┐
│需要共享│
│Python │
│对象? │
└───┬────┘
▼
┌────────┐
│Manager │
└────────┘
6. fork vs spawn vs forkserver
fork(Linux 默认) spawn(Windows/macOS 默认)
┌──────────────┐ ┌──────────────┐
│ 父进程 │ │ 父进程 │
│ ┌────────┐ │ │ ┌────────┐ │
│ │内存空间│ │ │ │内存空间│ │
│ └───┬────┘ │ │ └────────┘ │
└──────┼───────┘ └──────┬───────┘
│ │
│ fork() │ 创建新解释器
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 子进程 │ │ 子进程 │
│ ┌────────┐ │ │ ┌────────┐ │
│ │复制的 │ │ │ │全新的 │ │
│ │内存空间│ │ │ │内存空间│ │
│ └────────┘ │ │ └────────┘ │
└──────────────┘ └──────────────┘
✅ 快(直接复制) ✅ 安全(无残留状态)
❌ 不安全(继承锁/线程) ❌ 慢(重新加载模块)
7. 常用代码片段速查
python
# 创建子进程
p = mp.Process(target=func, args=(arg1,))
p.start()
p.join()
# 进程池
with mp.Pool(4) as pool:
results = pool.map(func, iterable)
# Queue 通信
queue = mp.Queue()
queue.put(data) # 生产
queue.get() # 消费
# Pipe 通信
parent, child = mp.Pipe()
parent.send(data)
child.recv()
# 共享内存
counter = mp.Value('i', 0)
with mp.Lock():
counter.value += 1