10

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

我不明白...为什么我不能将函数放在不同的文件中并导入它?

4

1 回答 1

16

快速回答:如果您希望函数能够访问引擎的全局命名空间,请使用 [1]@interactive装饰您的函数:IPython.parallel.util

从 IPython.parallel.util 导入交互式
f = 交互式(λ x:a+b+x)
ack = dview.apply(f, x)

实际解释:

IPython 用户命名空间本质上是模块__main__。当您这样做时,这是运行代码的地方execute('a = 5')

如果您以交互方式定义函数,则其模块也是__main__

拉姆 = λ x: a+b+x
林.__模块__
'__主要的__'

当引擎反序列化一个函数时,它会在函数模块的适当全局命名空间中执行此操作,因此__main__客户端中定义的函数也定义在__main__引擎上,因此可以访问a.

将其放入文件并导入后,函数不再附加到__main__,而是附加到模块dop

从多普进口多普
dop.__模块__
“滴”

该模块中通常定义的所有函数(包括 lambda)都将具有此值,因此当它们在 Engine 上解压缩时,它们的全局命名空间将是dop模块的命名空间,而不是 __main__,因此您的 'a' 不可访问。

出于这个原因,IPython 提供了一个简单的@interactive装饰器,它可以将任何函数解包,就好像它被定义在 中一样__main__,而不管函数实际定义在哪里。

有关差异的示例,请参考dop.py

从 IPython.parallel 导入客户端
从 IPython.parallel.util 导入交互式

a = 1

定义 dop(x):
    rc = 客户端()
    dview = rc[:]
    dview['a'] = 5
    f = λ x: a+x
    返回 dview.apply_sync(f, x)

定义 idop(x):
    rc = 客户端()
    dview = rc[:]
    dview['a'] = 5
    f = 交互式(λ x: a+x)
    返回 dview.apply_sync(f, x)

现在,dop将使用 dop 模块中的idop“a”,并将使用引擎命名空间中的“a”。两者之间的唯一区别是传递给 apply 的函数被包装在@interactive

从dop导入dop,idop
打印 dop(5) # 6
打印 idop(5) # 10

[1]:在 IPython >= 0.13(即将发布)中,@interactive也可以作为from IPython.parallel import interactive.

于 2012-06-02T02:40:16.020 回答