多进程时全局变量NameError,仅在子目录中出现
我有一个主程序,它使用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 个回答
解决方法是改变你的进程初始化方式:
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) 关于命名空间和作用域的教程页面 - 首先可以在这里查看内置、全局和局部命名空间的解释