【问题标题】:Replace pickle in Python multiprocessing lib在 Python 多处理库中替换 pickle
【发布时间】:2016-10-25 08:16:07
【问题描述】:

我需要执行下面的代码(我在 Python 3.5 中的真实代码库的简化版):

import multiprocessing
def forever(do_something=None):
    while True:
        do_something()

p = multiprocessing.Process(target=forever, args=(lambda: print("do  something"),))
p.start()

为了创建新进程,Python 需要腌制函数和作为目标传递的 lambda。 不幸的是,pickle 无法序列化 lambda,输出如下:

_pickle.PicklingError: Can't pickle <function <lambda> at 0x00C0D4B0>: attribute lookup <lambda> on __main__ failed

我发现cloudpickle 可以序列化和反序列化 lambda 和闭包,使用与 pickle 相同的接口。

如何强制 Python 多处理模块使用 cloudpickle 而不是 pickle?

显然破解标准库多处理的代码不是一种选择!

谢谢

查理

【问题讨论】:

  • 绝对有必要使用lambda 函数吗?
  • 是的,这是绝对必要的!
  • 为什么有必要?在您发布的代码中看起来没有必要。
  • 正如我所提到的,发布的代码是我的代码库的简化版本。更改代码库不是一种选择。请继续关注这个问题;-)
  • 也许检查cloudpickle的源代码,看看它是如何完成的?那么想办法包装 lambdas 呢?

标签: python lambda pickle python-multiprocessing


【解决方案1】:

试试multiprocess。它是multiprocessing 的一个分支,它使用dill 序列化程序而不是pickle——分支中没有其他变化。

我是作者。几年前我遇到了和你一样的问题,最终我决定破解标准库是我唯一的选择,因为multiprocessing 中的一些pickle 代码是用C++ 编写的。

>>> import multiprocess as mp
>>> p = mp.Pool()
>>> p.map(lambda x:x**2, range(4))
[0, 1, 4, 9]
>>> 

【讨论】:

  • 迈克,谢谢你的建议。事实上,你的 multiprocess+dill 是我第一次尝试解决这个问题。然而,我的代码在 Python 多进程处理中运行良好(即使没有 lambdas!),但在多进程和莳萝中不能完全正常工作。我认为这肯定是我的错,因为我如何在我的代码库中管理多处理。我认为唯一的方法是使用你的 multiprocess+dill 并尝试理解我的代码中的问题并最终解决它!谢谢
  • 如果您确实发现任一模块存在问题,请提交错误报告。
  • Mike,别担心,如果我发现任何问题,我一定会提交错误报告。您的库对 Python 非常有价值,我很乐意提供帮助!
  • @J.C.Rocamonde:我不确定你的观点/问题是什么。您提供的链接本质上是一个死项目(3 年陈旧),不知道multiprocess 中的实现。这本质上是重复劳动。基本上,是的,它到处都用dill 替换picklemultiprocess 也在 C++ 层做了相关的替换。在这样的文件中跟踪每个 python 版本的所有修改:github.com/uqfoundation/multiprocess/blob/master/py2.7/…
  • 我看到你做了什么改变。是的,multiprocess 是所有 python 版本的最新版本,包括 3.7。是的,您需要在 C 层替换,否则在请求 dill 时会使用 pickle。我的观点是,您派生的库中没有任何功能不在multiprocess 中,并且multiprocess 得到了更好的支持。我欢迎您向multiprocess 投稿,或者至少分叉它。
【解决方案2】:

如果你愿意做一些猴子补丁,一个快速的解决方法是替换pickle.Pickler

import pickle
import cloudpickle
pickle.Pickler = cloudpickle.Pickler

或者,在引入_pickle.Pickle 的最新Python 版本中,

from multiprocessing import reduction
import cloudpickle
reduction.ForkingPickler = cloudpickle.Pickler

请确保在导入 multiprocessing 之前执行此操作。这是一个完整的例子:

import pickle
import cloudpickle
pickle.Pickler = cloudpickle.Pickler

import multiprocessing as mp
mp.set_start_method('spawn', True)

def procprint(f):
    print(f())

if __name__ == '__main__':
    p = mp.Process(target=procprint, args=(lambda: "hello",))
    p.start()
    p.join()

顺便说一句,如果你的 start 方法是 fork,你就不需要做这些了,因为有了分叉,一开始就不需要腌制任何东西。

【讨论】:

    【解决方案3】:

    我正面临同样的问题。所以我做了一个小模块,它可以让 pythons mp 吃掉 lambdas。

    如果你有很多不同的不可腌制的东西,我也建议使用 dill 或 cloudpickle。

    https://github.com/cloasdata/lambdser

    pip install lambdser

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-12
      • 2016-05-23
      • 1970-01-01
      • 1970-01-01
      • 2020-04-10
      • 1970-01-01
      • 1970-01-01
      • 2019-01-30
      相关资源
      最近更新 更多