You need to enable JavaScript to run this app. Python multiprocessing spawn机制及父子进程内存状态差异疑问
优惠活动
大模型
产品
解决方案
定价
更多

Python multiprocessing spawn机制及父子进程内存状态差异疑问

关于multiprocessing spawn模式的相关说明与问题解答

spawn模式官方定义

父进程会启动一个全新的Python解释器进程,子进程仅会继承运行进程对象run()方法所需的必要资源。具体来说,父进程中不必要的文件描述符和句柄不会被继承,与fork或forkserver相比,使用该方法启动进程的速度要慢得多。支持Unix和Windows平台,是Windows和macOS系统的默认启动方式。

测试案例与运行现象

测试1:全局变量继承测试

import multiprocessing as mp
import signal

FOO = 10

def foo():
    assert FOO == 0

def test1():
    global FOO
    FOO = 0
    ctx = mp.get_context("spawn")
    p = ctx.Process(target=foo, args=())
    p.start()
    p.join()

if __name__ == "__main__":
    test1()

运行结果:子进程触发AssertionError,说明父进程运行时修改的全局变量FOO没有被子进程继承。


测试2:C级信号处理继承测试

import multiprocessing as mp
import signal

def bar():
    assert signal.getsignal(signal.SIGTERM) == signal.SIG_DFL

def test2():
    orignal = signal.getsignal(signal.SIGTERM)
    assert orignal == signal.SIG_DFL
    signal.signal(signal.SIGTERM, signal.SIG_IGN)
    ctx = mp.get_context("spawn")
    p = ctx.Process(target=bar, args=())
    p.start()
    p.join()

if __name__ == "__main__":
    test2()

运行结果:子进程触发AssertionError,说明父进程设置的SIG_IGN(C级内核态信号忽略规则)被子进程继承。


测试3:Python级信号处理继承测试

import multiprocessing as mp
import signal

def bar():
    # 断言子进程中没有父进程安装的处理函数
    assert signal.getsignal(signal.SIGTERM) == signal.SIG_DFL

def dummy(signum, frame):
    print("dummy", signum, frame)

def test3():
    orignal = signal.getsignal(signal.SIGTERM)
    assert orignal == signal.SIG_DFL

    signal.signal(signal.SIGTERM, dummy)
    ctx = mp.get_context("spawn")
    p = ctx.Process(target=bar, args=())
    p.start()
    p.join()

if __name__ == "__main__":
    test3()

运行结果:测试通过,说明父进程注册的Python自定义信号处理函数没有被子进程继承。

问题解答

1. spawn模式的完整执行流程

  • 父进程调用start()启动新进程时,首先会创建一个全新的空白Python解释器进程,不会复制父进程的内存空间
  • 父进程将运行目标函数所需的必要信息(目标函数、参数、必要的环境配置等)通过序列化(pickle)传递给子进程
  • 子进程启动后首先导入主模块,重新执行主模块的顶层代码获取基础上下文,仅会执行if __name__ == "__main__"之外的顶层代码,父进程在main块中运行时修改的运行时状态不会被执行
  • 子进程反序列化拿到的目标函数和参数,执行对应的逻辑
  • 非必要的资源(父进程运行时修改的全局状态、自定义Python级信号处理、未显式传递的文件句柄等)默认不会被继承

2. 为什么spawn模式下父子进程状态有时一致有时不一致?

核心判断标准是该状态属于操作系统内核级继承属性还是Python进程用户态自定义属性:

  • 状态一致的场景:如果修改的是操作系统内核层面关联到进程的属性,且该属性在进程创建时默认会被子进程继承,就会出现父子进程状态一致的情况。比如测试2中设置的signal.SIG_IGN是内核级的信号处理标记,新创建的进程默认会继承父进程的内核信号掩码和默认处理规则,因此子进程能拿到这个设置。
  • 状态不一致的场景:如果修改的是Python用户态的内存状态,spawn模式下子进程不会复制父进程的运行时内存,只会重新执行顶层代码初始化,因此父进程运行时修改的全局变量、自定义Python级信号处理函数(本质是Python内存中的函数对象)这类状态都不会被子进程继承,就会出现状态差异。比如测试1中修改的全局变量是Python内存中的数值,测试3中注册的是Python层的自定义函数,都不会被子进程拿到。

内容的提问来源于stack exchange,提问作者Izana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 07:06:06