如何在IPython.parallel中使用交互式定义的类?

ogr*_*sel 6 python parallel-processing ipython ipython-notebook

上下文

在连接到集群中的笔记本电脑的交互原型开发,我想定义一个类,无论是在客户端可用的__main__会话,并通过传递这样的情况下围绕集群引擎节点上交互方式更新到能够移动该类的实例LoadBalanced视图的参数.以下演示了典型的用户会话:

首先设置并行集群环境:

>>> from IPython.parallel import Client
>>> rc = Client()
>>> lview = rc.load_balanced_view()
>>> rc[:]
<DirectView [0, 1, 2]>
Run Code Online (Sandbox Code Playgroud)

在笔记本单元格中,让我们定义我们交互式编辑的组件的代码片段:

>>> class MyClass(object):
...     def __init__(self, parameter):
...         self.parameter = parameter
...
...     def update_something(self, some_data):
...         # do something smart here with some_data & internal state
...
...     def compute_something(self, other_data):
...         # do something smart here with other data & internal state
...         return something
...
Run Code Online (Sandbox Code Playgroud)

在下一个单元格中,让我们创建一个脚本来构建此类的实例,然后使用集群环境的负载平衡视图来评估各种输入参数上的组件:

>>> def process(obj, some_data, other_data):
...     obj.update_something(some_data)
...     return obj.compute_something(other_data)
...
>>> tasks = []
>>> some_instances = [MyClass(i) for i in range(10)]
>>> for obj in some_instances:
...    for some_data in data_source_1:
...         for other_data in data_source_2:
...             ar = lview.apply_async(process, obj, some_data, other_data)
...             tasks.append(ar)
...
>>> # wait for computation to end
>>> results = [ar.get() for ar in tasks] 
Run Code Online (Sandbox Code Playgroud)

问题

这显然不起作用,因为负载平衡视图的引擎将无法取消作为process函数的第一个参数传递的实例.进程函数定义本身成功传递,因为我假设它apply_async执行字节码检测(通过访问.code函数的属性)然后只为剩余的参数做一个简单的pickle.

可能的解决方案(对我不起作用)

  • 一种替代解决方案是%%px在持有类定义的单元格上使用单元格魔术MyClass.但是,这将阻止我在客户端脚本中构建也执行调度的类实例.我需要复制和粘贴,而不在其他细胞的细胞内容%%px魔法(或魔法,没有神奇的另一次执行单元一次两次),但这是乏味的时候我仍然编辑在迭代类的方法开发和评估设置.

  • 另一种解决方案是将类定义嵌入到process函数中,但我发现这不实用,因为我想在我的笔记本中稍后在其他函数中重用该类定义.

  • 或者,我可以停止使用一个类,只使用可以传递给引擎的函数,然后将第一个参数传递给apply_async.但是我不喜欢这样,因为我想以面向对象的方式对我的代码进行原型设计,以便以后从笔记本中提取并将结果类包含在面向对象的库中.笔记本会话用作协作原型工具,用于使用http://nbviewer.ipython.org发布者在开发人员之间交换想法.

  • 最后的替代方法是在python模块中将我的类写在文件系统上的文件中,并使用NFS将该文件发送到引擎PYTHONPATH.这有效但阻止我只在笔记本电脑环境中工作,这会破坏笔记本电脑中交互式原型设计的全部目的.

基本上,有没有办法以交互方式定义类,然后将其定义发送到引擎?

应该可以使用inspect.getsource客户端中的类来定义类定义,然后将源发送到引擎并使用eval内置函数,但遗憾的是源检查不适用于DummyMod内置模块中定义的类:

TypeError: <IPython.core.interactiveshell.DummyMod object at 0x10c2c4e50> is a built-in class

有没有办法检查类定义的字节码呢?

或者是否可以使用%%px魔法来在客户端和每个引擎上本地执行单元格的内容?

min*_*nrk 7

感谢您提供详细的问题(并在Twitter上ping我).

首先,也许它应该被视为一个错误,你不能只是推动类,因为简单的解决方案应该是

rc[:]['MyClass'] = MyClass
Run Code Online (Sandbox Code Playgroud)

但酸洗交互式定义的类只会产生一个引用('\x80\x02c__main__\nMyClass\nq\x01.'),给出你的DummyMod AttributeError.这可以在IPython的序列化中内部修复.

但是,对于实际的工作解决方案.

添加本地执行%%px非常简单,只需:

def pxlocal(line, cell):
    ip = get_ipython()
    ip.run_cell_magic("px", line, cell)
    ip.run_cell(cell)
get_ipython().register_magic_function(pxlocal, "cell")
Run Code Online (Sandbox Code Playgroud)

而且现在除了在本地运行单元格外%%pxlocal,还有一个魔法%%px.

那么你所要做的就是:

%%pxlocal

class MyClass(object):
    # etc
Run Code Online (Sandbox Code Playgroud)

到处定义你的课程.我将添加一个--local标志%%px,所以这个额外的步骤是没有必要的.

一个完整的,工作例如笔记本电脑.