共享内存值从对象中消失

时间:2015-04-08 18:29:19

标签: python queue multiprocessing shared-memory

这是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继承的好方法。 :)

1 个答案:

答案 0 :(得分:3)

它不是共享内存值的问题,它在队列对象本身上的变量消失了。

多处理在实现* nix forking模型的机器上与Windows创建过程模型的工作方式不同。在* nix上,当您创建multiprocessing进程时,父进程是分叉的,并且由于子进程具有父进程内存空间的写时复制视图,因此所有python对象(包括您的队列)都在儿童空间随时可以使用。

在Windows上,没有fork。创建一个新进程,并将父进程的相关部分进行pickle,发送给子进程并进行unpickled。这仅适用于可选对象,因此在Linux中运行的代码可能在Windows中失败。

如果您的对象不是本机可选择的,则可以实现__getstate____setstate__方法,这些方法返回对象的可选子集并从该状态重建对象。这是使用multiprocessing.Queue对象完成的。它不包含__getstate__中的变量,因此在重新创建子对象时,该变量不会包含在该对象中。

一个简单的解决方案是将您的数据放在其他位置。如果这不可行,请创建自己的multiprocessing.Queue子类并编写自己的__getstate____setstate__方法。