【问题标题】:Why is "pickle" and "multiprocessing picklability" so different in Python?为什么 Python 中的“pickle”和“multiprocessing picklability”如此不同?
【发布时间】:2019-11-16 15:58:42
【问题描述】:

在 Windows 上使用 Python 的 multiprocessing 将需要许多参数在传递给子进程时是“可挑选的”。

import multiprocessing

class Foobar:

   def __getstate__(self):
       print("I'm being pickled!")

def worker(foobar):
   print(foobar)

if __name__ == "__main__":
    # Uncomment this on Linux
    # multiprocessing.set_start_method("spawn")

    foobar = Foobar()
    process = multiprocessing.Process(target=worker, args=(foobar, ))
    process.start()
    process.join()

文档mentions this explicitly多次:

可腌制性

确保代理方法的参数是可挑选的。

[...]

比pickle/unpickle更好继承

当使用 spawn 或 forkserver 启动方法时,multiprocessing 中的许多类型需要是可挑选的,以便子进程可以使用它们。但是,通常应该避免使用管道或队列将共享对象发送到其他进程。相反,您应该安排程序,以便需要访问在其他地方创建的共享资源的进程可以从祖先进程继承它。

[...]

更易腌制

确保Process.__init__() 的所有参数都是可提取的。此外,如果您将 Process 子类化,请确保在调用 Process.start 方法时实例是可挑选的。

但是,我注意到“multiprocessingpickle”和标准 pickle 模块之间的两个主要区别,我无法理解所有这些。


multiprocessing.Queue() 不是“可挑选”的,但可以传递给子进程

import pickle
from multiprocessing import Queue, Process

def worker(queue):
    pass

if __name__ == "__main__":
    queue = Queue()

    # RuntimeError: Queue objects should only be shared between processes through inheritance
    pickle.dumps(queue)

    # Works fine
    process = Process(target=worker, args=(queue, ))
    process.start()
    process.join()
                                                                                                                                                                      

如果在“ma​​in”中定义,则不可腌制

import pickle
from multiprocessing import Process

def worker(foo):
    pass

if __name__ == "__main__":
    class Foo:
        pass

    foo = Foo()

    # Works fine
    pickle.dumps(foo)

    # AttributeError: Can't get attribute 'Foo' on <module '__mp_main__' from 'C:\\Users\\Delgan\\test.py'>
    process = Process(target=worker, args=(foo, ))
    process.start()
    process.join()

如果multiprocessing内部不使用pickle,那么这两种序列化对象方式的内在区别是什么?

另外,在多处理的上下文中,“继承”是什么意思?我应该怎么喜欢它而不是泡菜?

【问题讨论】:

    标签: python multiprocessing pickle


    【解决方案1】:

    将multiprocessing.Queue传递给子进程时,实际发送的是从pipe获取的文件描述符(或句柄),该文件描述符必须是父进程在创建子进程之前创建的。 pickle 的错误是为了防止尝试通过另一个 Queue(或类似通道)发送 Queue,因为那时使用它为时已晚。 (Unix 系统确实支持通过某些类型的套接字发送管道,但multiprocessing 不使用这些功能。)预计某些multiprocessing 类型可以发送到子进程,否则这些子进程会被没用,所以没有提到明显的矛盾。

    由于“spawn”启动方法无法使用已经创建的任何 Python 对象创建新进程,它必须重新导入主脚本以获得相关的函数/类定义。由于显而易见的原因,它不会像原来的运行那样设置__name__,所以任何依赖于该设置的东西都将不可用。 (这里,un酸洗失败了,这就是你手动酸洗工作的原因。)

    fork 方法在父对象(仅在 fork 时)仍然存在的情况下启动子对象;这就是继承的意思。

    【讨论】:

      猜你喜欢
      • 2015-10-18
      • 2015-10-18
      • 2014-09-13
      • 2016-01-06
      • 1970-01-01
      • 2012-02-16
      • 2016-01-19
      • 1970-01-01
      相关资源
      最近更新 更多