我假设多处理包使用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的建议编辑代码以符合编程准则)
多处理模块可以通过以下三种方式之一启动:spawn、fork或forkserver。默认情况下,在unix上,它分叉。这意味着,在新流程诞生的那一刻,不需要对已经加载到ram中的任何内容进行pickle。
如果您需要更直接地控制分叉的发生方式,则需要将启动设置更改为派生。为此,创建一个上下文
ctx=multiprocessing.get_context('spawn')
并将对CCD_ 3的所有呼叫替换为对ctx.foo()
的呼叫。当您这样做时,每个新进程都会作为一个新的python实例诞生;发送到其中的所有内容都将通过pickle发送,而不是直接的memcopy。
提醒:当您使用多处理时,您需要在'if __name__ == '__main__':
子句中启动一个进程:(请参阅编程指南)
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)
在窗户上,我看到
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上不调用。在Linux上,当您调用pickle.dumps
时,它首先调用__getstate__
,然后调用__setstate__
。了解多处理模块在不同平台上的不同表现是很有趣的。