【问题标题】:How to correctly import modules on engines in Jupyter Notebook for parallel processing?如何在 Jupyter Notebook 的引擎上正确导入模块以进行并行处理?
【发布时间】:2016-05-27 09:56:00
【问题描述】:

我希望运行一个令人尴尬的并行函数,该函数使用带有 Python 的 Jupyter Notebook 创建绘图(并最终将它们保存到文件中)(编辑 - 我找到了一种更简单的方法来做到这一点here)。我正在尝试最简单的版本,但出现导入错误。

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

导入文件中的位置从 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])

还有一个python文件名module.py

import matplotlib #[4]
def pll(x):
    matplotlib.pyplot.plot(x, '.')

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

[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

【问题讨论】:

  • 引擎是在本地运行还是在另一个系统上运行?
  • @frmdstryr 本地!都在同一台电脑上
  • 将 import #4 移到 pll 函数中是否有效?

标签: python python-3.x ipython jupyter-notebook ipython-parallel


【解决方案1】:

简答

当你使用模块函数时,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])

# module.py
from matplotlib import pyplot
def pll(x):
    pyplot.plot(x, '.')

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

import matplotlib
dview.apply_sync(matplotlib.use, 'agg')

或设置内联绘图:

%px %matplotlib inline

长答案

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

  • [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)

apply 将返回 ['why..'] 字符串列表,而不是您的本地 numpy 导入。 Python 不知道名称指的是模块或其他任何东西。这完全取决于使用什么命名空间来查找名称。这就是为什么您经常会看到类似于以下之一的交互式定义函数:

import module
%px import module
def foo():
    return module.x

或者这个:

def foo():
    import module
    return module.x

这两种方法都可以确保 foo 中的 module 映射到引擎上的导入模块:一种方法是在任何地方执行交互式命名空间导入并依赖全局命名空间查找。函数中的其他导入,所以不会出错。

sync_imports() 是一种纯 Python 方式,可以执行以下操作:

import module
%px import module

它在这里和那里都导入模块。如果你使用sync_imports,本地也不需要重复导入,因为本地已经导入了。

模块函数

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

需要考虑的重要一点:当你向引擎发送一个模块函数时,它只向函数发送一个引用,而不是函数或模块的内容。因此,如果from module import pll 在引擎上从客户端返回不同的内容,您将获得不同的行为。当在 ipython 中并行处理 local 模块,同时主动更改该模块时,这可能会使人们绊倒。在笔记本中重新加载该模块不会在引擎上重新加载该模块。它将发送相同的module.pll 参考。因此,如果您正在积极处理module.py,那么当该模块发生更改时,您将需要在任何地方致电reload(module)

【讨论】:

  • 非常有帮助,也很有教育意义!谢谢!
猜你喜欢
  • 2020-02-21
  • 2020-05-18
  • 2020-08-30
  • 2023-03-30
  • 2018-10-07
  • 2021-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多