这是Python中的一些奇怪的行为(2.7.9,Windows)我想问一下建议。
我试图在初始化中扩展一个带有变量的类,我想在两个进程(父进程和子进程)之间共享该类的对象。他们俩都会使用这个变量。
此代码可以正常工作:
# coding: utf-8
from multiprocessing import Process, Value
from time import sleep
class ExQueue(object):
def __init__(self, *args, **kwargs):
super(ExQueue, self).__init__(*args, **kwargs)
self.trust_me_this_name_is_unique = Value('L', 0)
def func(ex_queue):
print 'I am the child process. Is there a parameter: ',
print hasattr(ex_queue, 'trust_me_this_name_is_unique')
# this sleep is here to assure no printing overlapping
sleep(.5)
def main():
ex_queue = ExQueue()
print 'I am the parent process. Is there a parameter: ',
print hasattr(ex_queue, 'trust_me_this_name_is_unique')
child_process = Process(target=func, args=(ex_queue,))
child_process.start()
child_process.join()
print 'I am the parent process. Is there a parameter: ',
print hasattr(ex_queue, 'trust_me_this_name_is_unique')
if __name__ == '__main__':
main()
输出:
I am the parent process. Is there a parameter: True
I am the child process. Is there a parameter: True
I am the parent process. Is there a parameter: True
但是如果ExQueue
继承自Queue
类(来自multiprocessing.queues
模块的那个),则该技巧不起作用。
在开头添加:
from multiprocessing.queues import Queue
并更改
class ExQueue(object):
为:
class ExQueue(Queue):
输出将是:
I am the parent process. Is there a parameter: True
I am the child process. Is there a parameter: False
I am the parent process. Is there a parameter: True
因此,在子进程的ExQueue
示例中,没有trust_me_this_name_is_unique
变量。
关于我做错的任何想法?
谢谢!
UPD:在Mac OS上按预期工作。变量不会消失。
谢谢, tdelaney !你的回答很有帮助!
我将这两种方法添加到ExQueue
,现在它在Windows上发酵很好:
def __getstate__(self):
state = super(ExQueue, self).__getstate__()
return state + (self.trust_me_this_name_is_unique,)
def __setstate__(self, state):
state, self.trust_me_this_name_is_unique = state[:-1], state[-1]
super(ExQueue, self).__setstate__(state)
仍然不确定这是从Queue
继承的好方法。 :)
答案 0 :(得分:3)
它不是共享内存值的问题,它在队列对象本身上的变量消失了。
多处理在实现* nix forking模型的机器上与Windows创建过程模型的工作方式不同。在* nix上,当您创建multiprocessing
进程时,父进程是分叉的,并且由于子进程具有父进程内存空间的写时复制视图,因此所有python对象(包括您的队列)都在儿童空间随时可以使用。
在Windows上,没有fork
。创建一个新进程,并将父进程的相关部分进行pickle,发送给子进程并进行unpickled。这仅适用于可选对象,因此在Linux中运行的代码可能在Windows中失败。
如果您的对象不是本机可选择的,则可以实现__getstate__
和__setstate__
方法,这些方法返回对象的可选子集并从该状态重建对象。这是使用multiprocessing.Queue
对象完成的。它不包含__getstate__
中的变量,因此在重新创建子对象时,该变量不会包含在该对象中。
一个简单的解决方案是将您的数据放在其他位置。如果这不可行,请创建自己的multiprocessing.Queue
子类并编写自己的__getstate__
和__setstate__
方法。