张芷铭的个人博客

spawn 是跨平台的「干净启动」,fork 是 Unix 的「快速复制」。嵌套进程、跨平台开发首选 spawn。

核心差异

维度fork(Unix 专属)spawn(跨平台)
创建机制复制父进程地址空间(COW)启动新解释器,重新导入脚本
启动速度极快较慢
资源继承继承所有资源仅继承必要资源
线程安全父进程有活跃线程时易死锁天然线程安全
嵌套进程易出问题完美支持
跨平台差(Windows 不支持)好(全平台通用)

fork 原理

  • 调用 fork() 复制父进程整个地址空间
  • 子进程从 fork() 位置开始执行
  • 写时复制(COW):修改数据时才真正拷贝内存

spawn 原理

  • 启动全新 Python 解释器
  • 子进程重新导入当前脚本
  • 必须用 if __name__ == '__main__': 保护主逻辑

实践验证

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import multiprocessing
import os

GLOBAL_VAR = "父进程初始化"

def worker():
    print(f"子进程: {GLOBAL_VAR}")

if __name__ == '__main__':
    # fork:继承全局变量
    multiprocessing.set_start_method('fork')
    p = multiprocessing.Process(target=worker)
    p.start(); p.join()

    # spawn:重新初始化全局变量
    multiprocessing.set_start_method('spawn', force=True)
    p = multiprocessing.Process(target=worker)
    p.start(); p.join()

嵌套进程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
def nested_worker():
    print("嵌套子进程启动")

def parent_worker():
    p = multiprocessing.Process(target=nested_worker)
    p.start(); p.join()

if __name__ == '__main__':
    # fork:大概率死锁
    # spawn:稳定运行
    multiprocessing.set_start_method('spawn')
    p = multiprocessing.Process(target=parent_worker)
    p.start(); p.join()

避坑指南

问题解决方案
Windows 未加 if __name__ == '__main__':所有进程启动逻辑放保护块内
fork 导致死锁改用 spawn
spawn 启动慢用进程池复用
set_start_method 重复调用放脚本开头,或用 force=True

选择建议

场景推荐
纯 Linux/macOS、无嵌套、追求性能fork
跨平台、嵌套进程、有活跃线程spawn
数据处理、进程池spawn
简单脚本spawn(减少适配成本)

Comments