← 返回 Day 55 正文

Day 55 · 图解

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