我开始尝试使用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]。但是,如果我将代码分成不同的文件: dop.py:
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
我不明白...为什么我不能把这个函数放在另一个文件中并导入它?
答案 0 :(得分:16)
快速回答:如果您希望它能够访问引擎的全局命名空间,请使用@interactive
[1]中的IPython.parallel.util
来修饰您的函数:
from IPython.parallel.util import interactive f = interactive(lambda x: a+b+x) ack = dview.apply(f, x)
实际解释:
IPython用户名称空间本质上是模块__main__
。这是执行execute('a = 5')
时运行代码的地方。
如果以交互方式定义函数,其模块也是__main__
:
lam = lambda x: a+b+x lam.__module__ '__main__'
当Engine反序列化一个函数时,它会在函数模块的相应全局命名空间中这样做,因此客户端__main__
中定义的函数也在引擎的__main__
中定义,因此可以访问a
。
将文件放入文件并导入后,这些功能不再附加到__main__
,而是模块dop
:
from dop import dop dop.__module__ 'dop'
该模块中常规定义的所有函数(包括lambdas)都将具有此值,因此当它们在Engine上解压缩时,它们的全局命名空间将是dop
模块的命名空间,不是 __main__
,因此您的'a'无法访问。
出于这个原因,IPython提供了一个简单的@interactive
装饰器,导致任何函数被解压缩,就像它在__main__
中定义一样,无论函数实际定义在何处。
有关差异的示例,请参阅此dop.py
:
from IPython.parallel import Client from IPython.parallel.util import interactive a = 1 def dop(x): rc = Client() dview = rc[:] dview['a'] = 5 f = lambda x: a+x return dview.apply_sync(f, x) def idop(x): rc = Client() dview = rc[:] dview['a'] = 5 f = interactive(lambda x: a+x) return dview.apply_sync(f, x)
现在,dop
将使用dop模块中的“a”,idop
将使用引擎名称空间中的“a”。两者之间的唯一区别是传递给apply的函数包含在@interactive
:
from dop import dop, idop print dop(5) # 6 print idop(5) # 10
[1]:在IPython> = 0.13(即将发布的版本)中,@interactive
也可用作from IPython.parallel import interactive
,它始终应该是。{/ p>