【问题标题】:How to change the serialization method used by the multiprocessing module?如何更改多处理模块使用的序列化方法?
【发布时间】:2017-07-15 14:02:00
【问题描述】:

如何更改 Python multiprocessing 库使用的序列化方法?特别是,默认序列化方法使用pickle 库和该版本 Python 的默认 pickle 协议版本。默认的 pickle 协议是 Python 2.7 中的版本 2 和 Python 3.6 中的版本 3。如何在 Python 3.6 中将协议版本设置为 2,以便可以使用 multiprocessing 库中的一些类(如 ClientListener)在 Python 2.7 运行的服务器处理和客户端之间进行通信Python 3.6 运行的进程?

(旁注:作为测试,我修改了line 206 of multiprocessing/connection.py,将protocol=2 添加到dump() 调用中以强制协议版本为2,并且我的客户端/服务器进程在我的有限测试中运行,服务器由2.7 和 3.6 的客户端)。

在 Python 3.6 中,合并了 patch 以设置序列化程序,但补丁未记录在案,我还没有弄清楚如何使用它。这是我尝试使用它的方式(我也将它发布到我链接到的 Python 票证上):

pickle2reducer.py:

from multiprocessing.reduction import ForkingPickler, AbstractReducer

class ForkingPickler2(ForkingPickler):
    def __init__(self, *args):
        if len(args) > 1:
            args[1] = 2
        else:
            args.append(2)
        super().__init__(*args)

    @classmethod
    def dumps(cls, obj, protocol=2):
        return ForkingPickler.dumps(obj, protocol)


def dump(obj, file, protocol=2):
    ForkingPickler2(file, protocol).dump(obj)


class Pickle2Reducer(AbstractReducer):
    ForkingPickler = ForkingPickler2
    register = ForkingPickler2.register
    dump = dump

在我的客户中:

import pickle2reducer
multiprocessing.reducer = pickle2reducer.Pickle2Reducer()

在使用multiprocessing 做任何其他事情之前先放在顶部。执行此操作时,我仍然在由 Python 2.7 运行的服务器上看到 ValueError: unsupported pickle protocol: 3

【问题讨论】:

标签: python serialization pickle python-multiprocessing


【解决方案1】:

如果您使用多处理 "context" object,我相信您所指的补丁可以工作。

使用您的 pickle2reducer.py,您的客户端应该从:

import pickle2reducer
import multiprocessing as mp

ctx = mp.get_context()
ctx.reducer = pickle2reducer.Pickle2Reducer()

并且ctxmultiprocessing 具有相同的API。

希望有帮助!

【讨论】:

  • 这似乎是使用补丁的正确方法。我看不到如何在我的特定情况下使用上下文。我使用from multiprocessing.connection import Client, Listenerfrom multiprocessing.managers import BaseManager, NameSpaceProxy,这四个类都不能从上下文对象访问。我能够做到这一点:multiprocessing.context._default_context.reducer = Pickle2Reducer().
【解决方案2】:

非常感谢。它让我找到了我需要的解决方案。我最终做了类似的事情,但通过修改 Connection 类。对我来说,这比创建自己的完整子类并替换它更干净。

from multiprocessing.connection import Connection, _ForkingPickler, Client, Listener

def send_py2(self, obj):
    self._check_closed()
    self._check_writable()
    self._send_bytes(_ForkingPickler.dumps(obj, protocol=2))

Connection.send = send_py2

这正是来自 multiprocessing.connection 的代码,仅添加了 protocol=2 参数。

我想你甚至可以通过直接编辑 multiprocessing.reduction 中的原始 ForkingPickler 类来做同样的事情。

【讨论】:

  • 函数第三行有语法错误,你忘了self._send_bytes中的右括号
  • 谢谢!当您不小心复制和粘贴时,就会发生这种情况。刚刚更新了。
猜你喜欢
  • 2020-10-30
  • 1970-01-01
  • 2018-06-17
  • 1970-01-01
  • 1970-01-01
  • 2019-12-12
  • 2013-08-03
  • 1970-01-01
  • 2016-08-21
相关资源
最近更新 更多