Skip to main content
 首页 » 编程设计

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

2025年05月04日25lonelyxmas

我希望使用 Jupyter Notebook 和 Python 运行一个令人尴尬的并行函数来创建绘图(并最终将它们保存到文件中)(编辑 - 我发现了一种更简单的方法来做到这一点 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 

请您参考如下方法:

简答

当你使用模块函数时,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 parallel 的两个逻辑选择是 agg 如果你只是保存到文件,或者 %matplotlib inline 如果你想在笔记本中交互地查看绘图。使用聚合:

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

或设置内联绘图:

%px %matplotlib inline 

长答案

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

  • [1] 不,除非你想在全局变量中到处定义 module
  • [2] 不,除非你想在全局变量中到处定义 matplotlib
  • [3] 是的,这是将.pll传递给 map 所需要的
  • [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 不知道名称指的是模块或其他任何东西;这完全取决于使用什么 namespace 来查找名称。这就是为什么您会经常看到类似于以下之一的交互式定义函数:

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,则也不需要在本地重复导入,因为本地导入已经执行。

模块功能

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

需要考虑的重要事项:当您将模块函数发送到引擎时,它只会发送函数的引用,而不是函数或模块的内容。因此,如果 from module import pll 在引擎上从客户端返回不同的内容,您将获得不同的行为。当在 ipython 中并行使用 local 模块同时主动更改该模块时,这可能会使人们感到困惑。在笔记本中重新加载该模块不会在引擎上重新加载该模块。它将发送相同的 module.pll 引用。因此,如果您正在积极处理 module.py,您将需要在该模块更改时调用 reload(module) everywhere。