Python多进程中spawn为何远慢于fork?实测性能差异问询
问题:Python multiprocessing中spawn与fork的性能差异根源?
我在Python的multiprocessing模块中测试不同进程启动方法时发现:将method变量从"spawn"改为"fork"后,执行时间从9.5秒骤降至0.5秒。测试环境为Linux Pop!_OS,Python版本3.11。
测试代码如下:
import multiprocessing as mp from multiprocessing import Process, Value from time import time def increment_value(shared_integer): with shared_integer.get_lock(): shared_integer.value += 1 if __name__ == "__main__": method = "spawn" mp.set_start_method(method) start = time() for _ in range(200): integer = Value("i", 0) procs = [ Process(target=increment_value, args=(integer,)), Process(target=increment_value, args=(integer,)), ] for p in procs: p.start() for p in procs: p.join() assert integer.value == 2 print(f"{method} - Finished in {time() - start:.4f} seconds")
不同启动方法的运行结果:
spawn - Finished in 9.4275 seconds fork - Finished in 0.5316 seconds
我已知晓两种方法的进程启动原理,但对如此大的性能差异存疑,想明确代码中哪部分对性能影响最大?是spawn中的pickling操作?还是与锁有关?
回答
核心差异完全来自进程启动的开销,和锁几乎无关,pickling只是spawn开销的一部分,更关键的是spawn需要重新初始化整个Python解释器环境的成本。
具体拆解:
- fork的启动成本极低:在Linux上,fork通过操作系统级的地址空间复制实现,几乎瞬间完成。子进程直接继承父进程的Python解释器状态、已加载模块、全局变量等,无需额外初始化。
- spawn的启动成本极高:
- spawn会启动全新的Python解释器进程,需要重新加载所有模块、初始化解释器环境,这是最主要的开销来源。
- 虽然spawn需要通过pickle序列化目标函数和参数传递给子进程,但这部分开销和解释器初始化相比只是小头。
- 你的代码循环200次,每次启动2个spawn进程,相当于总共初始化了400次Python解释器,累加起来的开销就是9秒多的核心原因。
针对你的疑问:
- 锁的影响可以忽略:两种启动方式中
Value的锁操作逻辑完全一致,且每次锁操作仅为极短的整数自增,不会造成明显时间差异。 - pickling不是主要因素:真正的性能瓶颈是spawn每次启动都要重建Python运行环境,这部分开销远大于序列化参数的成本。
你可以通过减少循环次数验证:比如把循环改成1次,spawn的执行时间会降到零点几秒,而fork几乎仍接近0,这就能直观看到重复初始化解释器的累加开销。
内容的提问来源于stack exchange,提问作者S.B
相关产品推荐
相关产品推荐

