多处理忽略“__setstate__”

时间:2015-11-13 03:11:49

标签: pickle python-multiprocessing

我假设多处理包使用pickle在进程之间发送东西。但是,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)"

你应该得到像

这样的东西
module loaded in pid 1, hailing from pid 0
hello from pid 1
running report in pid 5, hailing from 1
5
10

我原本以为它会是“10”“10”而是“5”“10”。这意味着什么?

注意:根据用户3667217 的建议编辑符合编程指南的代码)

2 个答案:

答案 0 :(得分:4)

多处理模块可以启动以下三种方式之一:spawn,fork或forkserver。默认情况下,在unix上,它会分叉。这意味着在新流程诞生的那一刻,没有必要腌制已装入ram的任何东西。

如果您需要更直接地控制叉子的发生方式,则需要将启动设置更改为spawn。为此,请创建上下文

ctx=multiprocessing.get_context('spawn')

并通过调用multiprocessing.foo()替换对ctx.foo()的所有来电。当你这样做时,每个新进程都是作为一个新的python实例诞生的;发送到它的所有内容都将通过pickle发送,而不是直接memcopy。

答案 1 :(得分:1)

提醒:当您使用多处理时,您需要在'if __name__ == '__main__':子句中启动一个流程:(请参阅programming guidelines

import pickle
import multiprocessing

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

    def __setstate__(self, d):
        print('setstate happening')
        self.data = 10

    def __getstate__(self):
        return self.data
        print('getstate happening')

def report(ar,q):
    q.put(ar.data)

if __name__ == '__main__':
    ar = Tricky(5)
    q = multiprocessing.Queue()
    p = multiprocessing.Process(target=report, args=(ar, q))
    print('now starting process')
    p.start()
    print('now joining process')
    p.join()
    print('now getting results from queue')
    print(q.get())
    print('now getting pickle dumps')
    print(pickle.loads(pickle.dumps(ar)).data)   

在Windows上,我看到了

now starting process
now joining process
setstate happening
now getting results from queue 
10
now getting pickle dumps
setstate happening
10

在Ubuntu上,我看到了:

now starting process
now joining process
now getting results from queue
5
now getting pickle dumps
getstate happening
setstate happening
10

我想这应该回答你的问题。 multiprocess在Windows上调用__setstate__方法,但在Linux上不调用pickle.dumps方法。在Linux上,当您致电__getstate__时,请先致电__setstate__,然后致电p + Getauto(txtSearch.Text)。看到多处理模块在不同平台上的表现方式不同,这很有意思。