Python名称空间与ipython并行问题

时间:2012-06-01 20:59:30

标签: python python-2.7 parallel-processing ipython

我开始尝试使用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

我不明白...为什么我不能把这个函数放在另一个文件中并导入它?

1 个答案:

答案 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>