【问题标题】:Multiprocessing example giving AttributeError给出 AttributeError 的多处理示例
【发布时间】:2016-12-29 18:59:37
【问题描述】:

我正在尝试在我的代码中实现多处理,因此,我想我会从一些示例开始我的学习。我使用了documentation 中的第一个示例。

from multiprocessing import Pool
def f(x):
    return x*x

if __name__ == '__main__':
    with Pool(5) as p:
        print(p.map(f, [1, 2, 3]))

当我运行上面的代码时,我得到一个AttributeError: can't get attribute 'f' on <module '__main__' (built-in)>。我不知道为什么会收到此错误。如果有帮助,我也在使用 Python 3.5。

【问题讨论】:

  • 非常适合我(也在 python 3.5 上)。
  • 是的,在 Python 3.5 上也适用于我
  • 我应该补充一点,我也在使用 Jupyter Notebook 和 anaconda 作为我的解释器。但 anaconda 使用的是 python 3.5。
  • 我在使用 Python 3.6 的 Anaconda 的 Windows 10 上遇到错误。
  • 我在常规 python shell windows 10 Python 3.6 上收到错误

标签: python multithreading


【解决方案1】:

这个问题似乎是 multiprocessing.Pool 的设计特点。见https://bugs.python.org/issue25053。由于某种原因,Pool 并不总是适用于未在导入模块中定义的对象。所以你必须将你的函数写入不同的文件并导入模块。

文件:defs.py

def f(x):
    return x*x

文件:run.py

from multiprocessing import Pool
import defs

 if __name__ == '__main__':
    with Pool(5) as p:
        print(p.map(defs.f, [1, 2, 3]))

如果您使用 print 或其他内置函数,该示例应该可以工作。如果这不是错误(根据链接),则给定的示例选择不当。

【讨论】:

  • 当我运行脚本时,我得到:AttributeError: exit。原来问题出在“with”语句上,它需要一个带有“_ _ enter ”和“ exit __”方法的对象。所以我不得不将其更改为: p = Pool(5) 并且它起作用了。非常感谢!
  • 在创建Pool实例之前必须定义f()函数,否则worker看不到你的函数。但是,据我了解,您不必强制使用导入。
  • 非常有趣,在 pycharm 下运行代码时会出现此错误,但在 vscode 或 jupyter 中不会。所以
  • 对我来说,只是在 Pool 创建(或导入)之上定义函数 f() 并没有解决问题(Win 10,Python 3.6.8)
  • 我也没有 - Pool() 仍然无法处理这些建议。 ThreadPool() 按预期工作,但它是一个完全不同的函数。
【解决方案2】:

multiprocessing 模块在使用 IPython 时有一个主要限制:

此包中的功能要求 __main__ 模块是 孩子们可以导入。 [...] 这意味着一些示例,例如 因为multiprocessing.pool.Pool 示例在 交互式解释器。 [from the documentation]

幸运的是,有一个名为multiprocessmultiprocessing 模块的分支,它使用dill 而不是pickle 进行序列化并方便地克服了这个问题。

只需在您的导入中安装 multiprocess 并将 multiprocessing 替换为 multiprocess

import multiprocess as mp

def f(x):
    return x*x

with mp.Pool(5) as pool:
    print(pool.map(f, [1, 2, 3, 4, 5]))

当然,按照this answer 中的建议将代码外部化也可以,但我发现它非常不方便:这不是我使用 IPython 环境的原因(以及如何)。

multiprocessing 不能立即在 IPython 环境中工作,请改用它的 fork multiprocess

【讨论】:

  • multiprocess fork 似乎没有相同的模块 - 例如它找不到 Process、freeze_support 和 Queue?
  • 这个适用于 Jupyter notebook / IPython env,比之前的更好,但两者都适用!
  • 这应该是答案。很不错
  • 谢谢,简单的多处理在 2021 年无法使用,这绝对是疯了。
  • 这在 IPython (Python 3.9, macOS 11) 中完美运行!
【解决方案3】:

此答案适用于那些在 2021Windows 10 上遇到此错误的人。

自从我自己得到这个错误后,我已经对它进行了一些研究。运行 Python 3 官方文档中关于多处理的任何示例时出现此错误。

测试环境:

  • x86 Windows 10.0.19043.1165 + Python 3.9.2 - 出现错误
  • x86 Windows 10.0.19043.1165 + Python 3.9.6 - 出现错误
  • x86 Windows 10.0.19043.1110 + Python 3.9.6 - 出现错误
  • ARM Windows 10.0.21354.1 + Python 3.9.6 - 没有错误(来自 DEV 分支的版本)
  • ARM macOS 11.5.2 + Python 3.9.6 - 没有错误

我无法在其他条件下测试这种情况。但我的猜测是问题出在 Windows 上,因为开发者版本“10.0.21354.1”中没有这样的错误,但这个 ARM 版本可能有 x86 仿真。

另请注意,在 Python 3.9.2 发布时(2 月)没有此类错误。由于我一直在同一台计算机上工作,我对以前工作的代码停止工作的情况感到惊讶,只有 Windows 的版本发生了变化。

我无法在 Python 错误跟踪器中找到具有类似情况的错误请求(我可能搜索不佳)。标有“正确答案”的消息指的是不同的情况。该问题很容易重现,您可以尝试在新安装的 Windows 10 + Python 3 上遵循多处理文档中的任何示例。

稍后,我将有机会查看 Python 3.10 和最新版本的 Windows 10。 我也对 Windows 11 环境中的这种情况感兴趣。

如果您有关于此错误的信息(链接到错误跟踪器或类似内容),请务必分享。

目前我切换到 Linux 以继续工作。

【讨论】:

  • 我可以在 Windows 1902 x64 上重现该问题。 WSL 没有问题。 p = Process(target = f('bob')) 不起作用,因为 f('bob') 是在当前进程中计算的,而是 Processtarget 获取 f 的返回值,即 None。如果将f 更改为def f(name): return name,则会抛出错误,因为字符串name 不是callable
  • 非常感谢您的澄清。编辑了答案,删除了所有代码 - 它仍然没有帮助)
【解决方案4】:

如果您使用的是 Jupyter 笔记本(如 OP),则在单独的单元格中定义函数并执行该单元格首先可以解决问题。接受的答案也有效,但工作量更大。之前定义函数,即在池之上,是不够的。它必须在一个完全不同的笔记本单元中,首先执行。

【讨论】:

  • 不幸的是,这不起作用(不再)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-03
  • 2020-07-18
  • 1970-01-01
相关资源
最近更新 更多