多进程时全局变量NameError,仅在子目录中出现

1 投票
1 回答
2517 浏览
提问于 2025-04-18 12:16

我有一个主程序,它使用execfile来运行一个子进程中的脚本。这一切都很好,除非这个脚本在另一个目录里——那样一切就会出问题。

这段代码在 mainprocess.py 中:

from multiprocessing import Process

m = "subdir\\test.py"

if __name__ == '__main__':
    p = Process(target = execfile, args = (m,))
    p.start()

然后在一个叫做subdir的子目录里,我有 test.py

import time

def foo():
    print time.time()

foo()

当我运行 mainprocess.py 时,我会收到一个错误:

NameError: global name 'time' is not defined

不过,这个问题不仅仅是模块名的问题——有时候我在其他代码的函数名上也会遇到错误。

我试着在 mainprocess.py 中导入time模块,也在那里的 if 语句里面导入,但都没有效果。

有一种避免这个错误的方法(我还没试过),就是把 test.py 复制到父目录,并在文件里插入一行代码来用 os.chdir 回到原来的目录。不过,这样看起来有点不太整洁。

那么,这到底发生了什么呢?

1 个回答

1

解决方法是改变你的进程初始化方式:

p = Process(target=execfile, args=(m, {}))

老实说,我也不太确定为什么这样做有效。我知道这和导入time模块时使用的是哪个字典(局部变量还是全局变量)有关。看起来当你在test.py中导入时,它被当作局部变量,因为下面的代码可以正常工作:

import time        # no foo() anymore
print(time.time()) # the call to time.time() is in the same scope as the import

不过,下面的代码也能正常运行:

import time
def foo():
    global time
    print(time.time())
foo()

这个第二个例子让我明白了,导入的内容仍然被分配到了某种全局命名空间,只是我不知道具体是怎么回事。

如果你正常调用execfile(),而不是在子进程中,所有的东西都能正常运行。实际上,在主进程中调用execfile()之后,你可以在任何地方使用time模块,因为它已经被引入到同一个命名空间里。我认为,由于你是在子进程中启动它,所以没有模块级的命名空间来分配导入(execfile在调用时不会创建模块对象)。我觉得当我们在调用execfile时添加一个空字典时,我们实际上是在提供全局字典参数,这样就给了导入机制一个全局命名空间来分配time这个名字。

以下是一些背景链接:

1) 关于命名空间和作用域的教程页面 - 首先可以在这里查看内置、全局和局部命名空间的解释

2) Python文档中的execfile命令

3) 一个在非SO网站上非常相似的问题

撰写回答