我一直在阅读并重新阅读IPython文档/教程,我无法弄清楚这段特殊代码的问题。似乎函数dimensionless_run
对于传递给每个引擎的命名空间是不可见的,但我很困惑因为函数在__main__
中定义,并且作为全局的一部分清晰可见命名空间。
wrapper.py:
import math, os
def dimensionless_run(inputs):
output_file = open(inputs['fn'],'w')
...
return output_stats
def parallel_run(inputs):
import math, os ## Removing this line causes a NameError: global name 'math'
## is not defined.
folder = inputs['folder']
zfill_amt = int(math.floor(math.log10(inputs['num_iters'])))
for i in range(inputs['num_iters']):
run_num_str = str(i).zfill(zfill_amt)
if not os.path.exists(folder + '/'):
os.mkdir(folder)
dimensionless_run(inputs)
return
if __name__ == "__main__":
inputs = [input1,input2,...]
client = Client()
lbview = client.load_balanced_view()
lbview.block = True
for x in sorted(globals().items()):
print x
lbview.map(parallel_run,inputs)
在ipcluster start --n=6
之后执行此代码会生成已排序的全局字典,包括math
和os
模块以及parallel_run
和dimensionless_run
函数。接下来是一个IPython.parallel.error.CompositeError:调用方法的一个或多个异常:parallel_run,它由大量[n:apply]: NameError: global name 'dimensionless_run' is not defined
组成,其中n从0-5开始。
有两件事我不明白,而且它们之间有明显的联系。
dimensionless_run
?import math, os
必须在里面定义parallel_run? 已编辑:根本没有太多的命名空间错误 - 我在一个不包含代码的目录中执行ipcluster start --n=6
。要修复它,我需要做的就是在我的代码目录中执行start命令。我还通过添加以下行来修复它:
inputs = input_pairs
os.system("ipcluster start -n 6") #NEW
client = Client()
...
lbview.map(parallel_run,inputs)
os.system("ipcluster stop") #NEW
在正确的位置启动所需的群集。
答案 0 :(得分:7)
这主要是Python name space issues with IPython.parallel的副本,其中有更详细的答案,但要点:
当客户端将parallel_run
发送到引擎时,它只发送该函数,而不是发送定义函数的整个命名空间(__main__
模块)。因此,在运行远程parallel_run
时,math
或os
或dimensionless_run
的查找将首先在locals()
中查找(已在函数中定义的内容,即您的函数内导入),然后在globals()
,即引擎上的__main__
模块 。
有多种方法可以确保引擎上的名称可用,但最简单的方法是明确定义/发送它们到引擎(引擎上的交互式命名空间 __main__
,就像它在IPython本地一样):
client[:].execute("import os, math")
client[:]['dimensionless_run'] = dimensionless_run
在您开始运行之前,在这种情况下,一切都应该按预期运行。
这是交互式/脚本中定义的模块所特有的问题 - 如果此文件是模块而不是脚本,则不会出现此问题,例如
from mymod import parallel_run
lbview.map(parallel_run, inputs)
在这种情况下,globals()
是模块全局变量,在各处通常都是相同的。