You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何设置recurse=True会导致dill不识别函数中的全局变量?

dill序列化含全局变量函数时recurse=True导致加载后全局变量未定义的原因分析

正常运行场景

以下代码可正常执行,子进程通过initializer设置全局变量foo,worker函数能正确读取该变量:

import multiprocessing
import dill

def initializer():
    global foo
    foo = 1

def worker(arg):
    return foo
   
with multiprocessing.Pool(2, initializer) as pool:
    res = pool.map(worker, range(10))

print(res)

输出结果:[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

序列化后出错的场景

当使用dill.dump(..., recurse=True)序列化函数并重新加载后,运行会抛出NameError:

import multiprocessing
import dill

def initializer():
    global foo
    foo = 1

def worker(arg):
    return foo

with open('funcs.pkl', 'wb') as f:
    dill.dump((initializer, worker), f, recurse=True)

with open('funcs.pkl', 'rb') as f:
    initializer, worker = dill.load(f)

with multiprocessing.Pool(2, initializer) as pool:
    res = pool.map(worker, range(2))

错误信息:

File "/tmp/ipykernel_158597/1183951641.py", line 9, in worker
    return foo
           ^^^
NameError: name 'foo' is not defined

原因分析

核心在于dill的recurse参数对函数全局命名空间的处理逻辑:

  • 当recurse=False时:dill仅序列化函数本身的字节码和基本元数据,不会递归捕获函数引用的全局上下文。加载后,函数仍然在当前进程/子进程的全局命名空间中执行,initializer在子进程中设置的全局变量foo会直接进入worker的运行命名空间,因此能被正常读取。
  • 当recurse=True时:dill会递归序列化函数的整个执行上下文,包括函数绑定的原始全局命名空间快照。加载后,worker函数的全局变量引用被固定到序列化时的空命名空间(此时foo还未定义)。而multiprocessing的子进程中,initializer是在子进程的全局命名空间中设置foo,这个命名空间和worker绑定的序列化快照命名空间完全隔离,因此worker找不到foo,抛出NameError。

简单来说,recurse=True把函数和它的“原始环境”绑定死了,后续子进程中动态设置的全局变量无法进入这个绑定的环境,导致变量未定义。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 07:01:03