多处理忽略“__setstate__”
multiprocessing ignores "__setstate__"
我假设 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 的建议编辑代码以符合编程指南)
提醒:当您使用多重处理时,您需要在 '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 上调用。在 Linux 上,当你调用 pickle.dumps
时,它首先调用 __getstate__
,然后是 __setstate__
。有趣的是,多处理模块在不同平台上的行为有何不同。
多处理模块可以通过以下三种方式之一启动:spawn、fork 或 forkserver。默认情况下,在 unix 上,它会分叉。这意味着在新进程诞生时不需要 pickle 任何已经加载到 ram 中的东西。
如果您需要更直接地控制分叉的发生方式,您需要将启动设置更改为生成。为此,创建上下文
ctx=multiprocessing.get_context('spawn')
并将所有对 multiprocessing.foo()
的调用替换为对 ctx.foo()
的调用。当您这样做时,每个新进程都会作为一个新的 python 实例诞生;发送到其中的所有内容都将通过 pickle 发送,而不是直接 memcopy。
我假设 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 的建议编辑代码以符合编程指南)
提醒:当您使用多重处理时,您需要在 '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 上调用。在 Linux 上,当你调用 pickle.dumps
时,它首先调用 __getstate__
,然后是 __setstate__
。有趣的是,多处理模块在不同平台上的行为有何不同。
多处理模块可以通过以下三种方式之一启动:spawn、fork 或 forkserver。默认情况下,在 unix 上,它会分叉。这意味着在新进程诞生时不需要 pickle 任何已经加载到 ram 中的东西。
如果您需要更直接地控制分叉的发生方式,您需要将启动设置更改为生成。为此,创建上下文
ctx=multiprocessing.get_context('spawn')
并将所有对 multiprocessing.foo()
的调用替换为对 ctx.foo()
的调用。当您这样做时,每个新进程都会作为一个新的 python 实例诞生;发送到其中的所有内容都将通过 pickle 发送,而不是直接 memcopy。