我开始尝试使用ipython并行工具,并遇到了一个问题。我启动python引擎时使用:
ipcluster start -n 3
然后以下代码运行正常:
from IPython.parallel import Client
def dop(x):
rc = Client()
dview = rc[:]
dview.block=True
dview.execute('a = 5')
dview['b'] = 10
ack = dview.apply(lambda x: a+b+x, x)
return ack
ack = dop(27)
print ack
按原样返回[42,42,42]。但是如果我把代码分解成不同的文件:
打印日期:
from IPython.parallel import Client
def dop(x):
rc = Client()
dview = rc[:]
dview.block=True
dview.execute('a = 5')
dview['b'] = 10
print dview['a']
ack = dview.apply(lambda x: a+b+x, x)
return ack
并尝试以下操作:
from dop import dop
ack = dop(27)
print ack
我从每个引擎得到错误:
[0:apply]: NameError: global name 'a' is not defined
[1:apply]: NameError: global name 'a' is not defined
[2:apply]: NameError: global name 'a' is not defined
我不明白……为什么我不能把函数放在另一个文件中并导入它?
最佳答案
快速回答:如果您希望函数能够访问引擎的全局命名空间,请使用来自@interactive
[1]的IPython.parallel.util
来修饰您的函数:
从ipython.parallel.util导入Interactive
F=交互式(lambda x:a+b+x)
ACK=D视图应用(F,X)
实际解释:
ipython用户名称空间本质上是模块__main__
。这是在执行execute('a = 5')
时运行代码的地方。
如果以交互方式定义函数,则其模块也为:
lam=lambda x:a+b+x
激光模组__
'主'
当引擎取消对某个函数的序列化时,它会在函数模块的相应全局命名空间中进行此操作,因此在客户端的__main__
中定义的函数也会在引擎的__main__
中定义,因此可以访问__main__
。
一旦将其放入文件并导入,那么函数就不再附加到a
中,而是模块__main__
:
从DOP导入DOP
DOP模块__
“DOP”
该模块(包括lambda)中常规定义的所有函数都将具有此值,因此当在引擎上解包它们时,它们的全局命名空间将是dop
模块的全局命名空间,而不是dop
,因此您的“a”不可访问。
因此,ipython提供了一个简单的__main__
修饰器,它可以像在@interactive
中定义的那样对任何函数进行解包,而不管函数实际上是在哪里定义的。
对于差异的一个例子,请看下面的例子:
来自ipython.parallel导入客户端
从ipython.parallel.util导入Interactive
A=1
定义DOP(X):
rc=客户机()
dView=rc[:]
视图[‘A’]=5
F=λx:a+x
返回dview.应用同步(f,x)
定义IDOP(X):
rc=客户机()
dView=rc[:]
视图[‘A’]=5
F=交互式(lambda x:a+x)
返回dview.应用同步(f,x)
现在,__main__
将使用dop模块中的“a”,dop.py
将使用引擎名称空间中的“a”。两者之间的唯一区别是传递给apply的函数被包装在dop
中:
从DOP导入DOP,IDOP
打印DOP(5)6
打印IDOP(5)10
[1]:在ipython>=0.13(即将发布的版本)中,idop
也可以作为@interactive
提供,在这里它应该一直存在。