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的建议,对代码进行了编辑以符合编程准则)
多重处理模块可以启动以下三种方式之一:spawn,fork或forkserver。在UNIX上,默认情况下会分叉。这意味着在新流程诞生之时,无需腌制已经加载到ram中的任何东西。
如果需要直接控制派生叉的方式,则需要将启动设置更改为“ spawn”。为此,请创建一个上下文
ctx=multiprocessing.get_context('spawn')
Run Code Online (Sandbox Code Playgroud)
并将所有对multiprocessing.foo()的呼叫替换为对的呼叫ctx.foo()。执行此操作时,每个新进程都会作为一个新的python实例诞生;发送到其中的所有内容都将通过泡菜发送,而不是直接进行内存复制。