如何在Jupyter Notebook中正确导入引擎上的模块进行并行处理?

got*_*ota 1 python ipython python-3.x ipython-parallel jupyter-notebook

我想用Jupyter笔记本采用Python来运行一个尴尬的并行功能,创建曲线(并最终将它们保存到一个文件)(编辑-我发现了一个更简单的方法来做到这正是在这里).我正在尝试最简单的版本,我收到导入错误.

我应该在哪里以及为什么要导入相关模块?我想我到处输入它们只是为了确定但我仍然有错误!

导入文件中的位置编号为1-4

[1]这条线真的有必要吗?为什么?

[2]这条线真的有必要吗?为什么?

[3]这条线真的有必要吗?为什么?

[4]这条线真的有必要吗?为什么?

以下是我的文件:jupyter笔记本文件:

import ipyparallel
clients = ipyparallel.Client()
print(clients.ids)
dview = clients[:]
with dview.sync_imports():
    import module #[1]
    import matplotlib #[2]
import module #[3]
dview.map_sync(module.pll, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
Run Code Online (Sandbox Code Playgroud)

和一个python文件名module.py

import matplotlib #[4]
def pll(x):
    matplotlib.pyplot.plot(x, '.')
Run Code Online (Sandbox Code Playgroud)

当我运行笔记本时,我得到以下输出

[0, 1, 2, 3, 4, 5]
importing module on engine(s)
importing matplotlib on engine(s)
[Engine Exception]
NameErrorTraceback (most recent call last)<string> in <module>()
(...)
NameError: name 'matplotlib' is not defined
Run Code Online (Sandbox Code Playgroud)

min*_*nrk 5

简短的回答

使用模块功能时不需要sync_imports.这应该足够了:

# notebook:
import ipyparallel as ipp
client = ipp.Client()
dview = client[:]

import module
dview.map_sync(module.pll, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
Run Code Online (Sandbox Code Playgroud)

# module.py
from matplotlib import pyplot
def pll(x):
    pyplot.plot(x, '.')
Run Code Online (Sandbox Code Playgroud)

一个警告:您几乎肯定会想要设置matplotlib以在引擎上使用非默认后端.您必须在导入pyplot之前执行此操作.ipython parallel的两个逻辑选择是agg你只是保存到文件,或者%matplotlib inline你想在笔记本中以交互方式查看图.要使用agg:

import matplotlib
dview.apply_sync(matplotlib.use, 'agg')
Run Code Online (Sandbox Code Playgroud)

或设置内联绘图:

%px %matplotlib inline
Run Code Online (Sandbox Code Playgroud)

答案很长

要回答您的项目符号问题:

  • [1]不,除非你想module在全局变量中定义
  • [2]不,除非你想matplotlib在全局变量中定义
  • [3]是的,这需要传递.pll给地图
  • [4]是的,因为它module是一个不同的命名空间__main__,这是所有笔记本代码运行的地方.

在处理需要导入的内容时,您需要考虑两种情况:

交互式定义的功能

交互式定义函数(即,def foo()在笔记本中)时,将在交互式命名空间中执行名称查找,并且引擎上的交互式命名空间可能在引擎和客户端之间不同.例如,你可以看到:

import numpy
%px numpy = 'whywouldyoudothis'

def return_numpy():
    return numpy # resolved locally *on engines*
dview.apply_sync(return_numpy)
Run Code Online (Sandbox Code Playgroud)

其中,apply将返回["为什么.."]字符串,而不是你的本地列表numpy导入.Python不知道名称是指模块还是其他任何东西; 这都是用于查找名称的命名空间的问题.这就是为什么您经常会看到交互式定义的函数,它们看起来像这样:

import module
%px import module
def foo():
    return module.x
Run Code Online (Sandbox Code Playgroud)

或这个:

def foo():
    import module
    return module.x
Run Code Online (Sandbox Code Playgroud)

两者都是确保modulefoo映射到引擎上的导入模块的方法:一个在任何地方执行交互式命名空间导入并依赖于全局命名空间查找.其他进口功能,所以不能错.

sync_imports() 是一种纯Python的方式来做同样的事情:

import module
%px import module
Run Code Online (Sandbox Code Playgroud)

它在这里和那里导入模块.如果使用sync_imports,则不必在本地重复导入,因为已执行本地导入.

模块功能

如果函数是在模块中定义的,那么它将在其模块中找到全局变量,而不是在交互式命名空间中.因此,import matplotlib在您的笔记本中,调用matplotlib名称时是否定义名称没有影响module.pll.同样,在模块中导入matplotlib并不会使它在交互式命名空间中可用.

需要考虑的重要事项:当您将模块函数发送到引擎时,它只发送对函数的引用,而不是函数或模块的内容.因此,如果from module import pll从客户端返回引擎上的不同内容,您将获得不同的行为.在主动更改该模块的同时,在ipython并行使用本地模块时,这会使人们绊倒.在笔记本重新加载该模块不会重新加载引擎上的模块.它将发送相同的module.pll参考.因此,如果您正在积极地工作module.py,那么当该模块发生变化时,您将需要在reload(module) 任何地方呼叫.