子类化multiprocessing.queue.Queue:由父级设置的属性对子级不可用?

时间:2018-09-11 14:33:53

标签: python multiprocessing pickle

我将多处理库与python 3.7一起使用,其父进程通过队列与子进程进行对话。我可以使用multiprocessing.queue.Queue很好,但是当我通过子类向队列添加一些额外的功能时,它们在父级中的设置就很好了,但是在子级访问时似乎丢失了。知道如何让属性保留在孩子中吗?

import sys
import time
import multiprocessing
import multiprocessing.queues

# Subclass multiprocessing.queue.Queue to add some useful features
class q_class(multiprocessing.queues.Queue):
    def __init__(self):
        self.report_bottlenecks = False
        self.bottleneck_time = 1.0 #in seconds
        super(q_class, self).__init__(ctx=multiprocessing.get_context())
    def put(self,header,payload=None):
        message = {}
        message['header'] = header
        message['payload'] = payload
        message['put_time'] = time.time()
        super(q_class, self).put(message)
    def get(self):
        message = super(q_class, self).get()
        message['get_time'] = time.time()
        message['queue_time'] = message['get_time'] - message['put_time']
        if self.report_bottlenecks:
            if message['queue_time']>self.bottleneck_time:
                self.debug.print('Queue bottleneck: '+str(int(message['queue_time']))+' seconds.')
        return(message)

def function_for_child_to_run(the_q):
    print('Child process started')
    print(the_q.report_bottlenecks) #currently causes an AttributeError: 'q_class' object has no attribute 'report_bottlenecks'

if __name__ == '__main__':
    multiprocessing.set_start_method('forkserver')
    my_q = q_class()
    print(my_q.report_bottlenecks) #should print "False"
    process = multiprocessing.Process( target=function_for_child_to_run , args=(my_q,) )
    process.start()
    time.sleep(2) #give the child time to start & print
    process.join()
    sys.exit()

1 个答案:

答案 0 :(得分:0)

要与forkserver一起使用,必须对队列进行腌制。 multiprocessing.queues.Queue定义了__getstate____setstate__方法来酸洗和取消酸洗实例属性。将属性添加到子类Queue时,必须使用自定义属性扩展这两种方法,否则它们会丢失。

将此添加到您的代码中:

from multiprocessing import context
...
class QClass(multiprocessing.queues.Queue):     
    ...
    def __getstate__(self):
        context.assert_spawning(self)
        return (self._ignore_epipe, self._maxsize, self._reader, self._writer,
                self._rlock, self._wlock, self._sem, self._opid,
                self.report_bottlenecks, self.bottleneck_time)  # <---

    def __setstate__(self, state):
        (self._ignore_epipe, self._maxsize, self._reader, self._writer,
         self._rlock, self._wlock, self._sem, self._opid,
         self.report_bottlenecks, self.bottleneck_time) = state  # <---
        self._after_fork()