CPU密集型任务必须用multiprocessing,I/O密集型优先选threading或asyncio;混合型需拆分处理,进程间通信避免直接共享内存,Windows下务必用if name == '__main__':保护。

能。只要任务是 CPU 密集型(比如数值计算、HTML 解析、图像处理),用 multiprocessing 就能真正并行,把 8 核 CPU 跑到 700%+ 利用率;但如果是纯网络请求,多进程反而可能更慢——I/O 密集型任务优先选 threading 或 asyncio。
什么时候该用 multiprocessing 而不是 threading
判断依据不是“想快”,而是任务类型:
- CPU 密集型:正则匹配大文本、
numpy矩阵运算、BeautifulSoup解析 10MB HTML、PDF 文字提取 —— 必须用multiprocessing,否则线程全卡在 GIL 上 - I/O 密集型:发 HTTP 请求、读写文件、数据库查询 ——
threading更轻量,multiprocessing启动开销大,还可能触发连接数限制 - 混合型(比如爬虫:请求 + 解析):用
multiprocessing处理解析部分,请求部分用threading或asyncio,别全塞进一个进程里
Process 和 Pool 哪个更适合你的场景
Process 是手动控制单个进程,Pool 是自动管理一批同构任务。选错会导致代码冗余或资源浪费:
- 用
Process:需要精细控制生命周期(比如某个进程要常驻、监听信号)、不同进程执行不同逻辑、或需定制启动参数(如start_method='spawn') - 用
Pool:批量处理相同函数(如对 1000 张图片调用同一resize_image())、想自动负载均衡、避免自己写join()和错误传播逻辑 - 注意:
Pool默认进程数是os.cpu_count(),但如果你的任务含 I/O 等待,可设为os.cpu_count() + 2;纯 CPU 计算建议严格等于物理核心数,超了反而因上下文切换拖慢整体速度
Windows 下 fork vs spawn 的坑必须绕开
Windows 不支持 fork,默认用 spawn —— 子进程会重新导入主模块,如果顶层有可执行代码(比如没包在 if __name__ == '__main__': 里),就会重复运行甚至死循环:
立即学习“Python免费学习笔记(深入)”;
- 所有
Process()或Pool()创建代码,必须放在if __name__ == '__main__':块内 - 不要在模块顶层写
p = multiprocessing.Process(...); p.start(),否则 Linux/macOS 可能侥幸跑通,Windows 直接报错或静默重复执行 - 如果你依赖全局变量(如配置字典),
spawn下它们不会自动继承,得显式传参;fork虽能继承,但状态可能不一致(比如已打开的文件句柄)
进程间通信别直接共享内存
进程内存隔离是安全前提,强行“共享”反而容易出错:
- 传简单数据(列表、字典、数字):用
Pool.map()或Process的args参数,底层靠pickle序列化,够用且安全 - 需要实时通信(如生产者-消费者):用
Queue或Pipe,Queue是线程/进程安全的,Pipe更快但只支持两个端点 - 避免用
Manager().dict()或Manager().list():性能差(每次访问都跨进程调用),仅适合小量控制信息(如“是否中止”的标志位) - 真要共享大数组(如图像像素矩阵):用
Array或Value+Lock,但必须手动加锁,否则数据损坏
最常被忽略的一点:不是所有对象都能被 pickle。lambda 函数、嵌套类、带绑定方法的实例,传给 Process 或 Pool 时会直接抛 AttributeError: Can't pickle ... —— 解决办法只有把目标函数定义在模块顶层,别嵌套、别用 lambda。


















