多处理忽略“ __setstate__”

Jac*_*per 1 python pickle multiprocessing python-multiprocessing

我假设多处理程序包使用pickle在进程之间发送消息。但是,泡菜要注意对象的__getstate____setstate__方法。多处理似乎忽略了它们。它是否正确?我感到困惑吗?

要复制,请安装docker,然后在命令行中键入

$ docker run python:3.4 python -c "import pickle
import multiprocessing
import os

class Tricky:
    def __init__(self,x):
        self.data=x

    def __setstate__(self,d):
        self.data=10

    def __getstate__(self):
        return {}

def report(ar,q):
    print('running report in pid %d, hailing from %d'%(os.getpid(),os.getppid()))
    q.put(ar.data)

print('module loaded in pid %d, hailing from pid %d'%(os.getpid(),os.getppid()))
if __name__ == '__main__':
    print('hello from pid %d'%os.getpid())
    ar = Tricky(5)
    q = multiprocessing.Queue()
    p = multiprocessing.Process(target=report, args=(ar, q))
    p.start()
    p.join()
    print(q.get())
    print(pickle.loads(pickle.dumps(ar)).data)"
Run Code Online (Sandbox Code Playgroud)

你应该得到类似

module loaded in pid 1, hailing from pid 0
hello from pid 1
running report in pid 5, hailing from 1
5
10
Run Code Online (Sandbox Code Playgroud)

我本以为它应该是“ 10”“ 10”,但实际上是“ 5”“ 10”。什么意思

注意:根据用户3667217的建议,对代码进行了编辑以符合编程准则

Jac*_*per 5

多重处理模块可以启动以下三种方式之一:spawn,fork或forkserver。在UNIX上,默认情况下会分叉。这意味着在新流程诞生之时,无需腌制已经加载到ram中的任何东西。

如果需要直接控制派生叉的方式,则需要将启动设置更改为“ spawn”。为此,请创建一个上下文

ctx=multiprocessing.get_context('spawn')
Run Code Online (Sandbox Code Playgroud)

并将所有对multiprocessing.foo()的呼叫替换为对的呼叫ctx.foo()。执行此操作时,每个新进程都会作为一个新的python实例诞生;发送到其中的所有内容都将通过泡菜发送,而不是直接进行内存复制。