如何子类化multiprocessing.JoinableQueue

时间:2014-08-12 09:43:51

标签: python multithreading multiprocessing

我正在尝试子类multiprocessing.JoinableQueue,以便我可以跟踪已跳过而不是已完成的作业。我正在使用JoinableQueue将作业传递给一组multiprocessing.Process并且我有一个threading.Thread填充队列。这是我的实施尝试:

import multiprocessing

class InputJobQueue(multiprocessing.JoinableQueue):

    def __init__(self, max_size):
        super(InputJobQueue, self).__init__(0)
        self._max_size = max_size
        self._skipped_job_count = 0

    def isFull(self):
        return self.qsize() >= self._max_size

    def taskSkipped(self):
        self._skipped_job_count += 1
        self.task_done()

但是,我遇到了记录here

的问题
class InputJobQueue(multiprocessing.JoinableQueue):
TypeError
:
Error when calling the metaclass bases
    function() argument 1 must be code, not str

查看multiprocessing中的代码,我发现实际的类位于multiprocessing.queues。所以我试着扩展那个类:

import multiprocessing.queues

class InputJobQueue(multiprocessing.queues.JoinableQueue):

    def __init__(self, max_size):
        super(InputJobQueue, self).__init__(0)
        self._max_size = max_size
        self._skipped_job_count = 0

    def isFull(self):
        return self.qsize() >= self._max_size

    def taskSkipped(self):
        self._skipped_job_count += 1
        self.task_done()

但是我得到了不一致的结果:有时我的自定义属性存在,有时他们不会。例如。我的一个工作进程中报告了以下错误:

AttributeError: 'InputJobQueue' object has no attribute '_max_size'

我缺少什么来继承multiprocessing.JoinableQueue

2 个答案:

答案 0 :(得分:4)

使用multiprocessing,进程之间神奇地共享像JoinableQueue这样的对象的方式是明确共享核心同步对象,并挑选“包装”东西来传递管道。

如果您了解酸洗的工作原理,您可以查看JoinableQueue的来源,看看它是否正在使用__getstate__ / __setstate__。因此,您只需要覆盖它们以添加自己的属性。像这样:

def __getstate__(self):
    return super(InputJobQueue, self).__getstate__() + (self._max_size,)

def __setstate__(self, state):
    super(InputJobQueue, self).__setstate__(state[:-1])
    self._max_size = state[-1]

我不承诺这实际上是工作,因为很明显这些类不是设计为子类(你引用的错误的建议修复是记录类不能被子类化并找到一种方法使错误消息更好......)。但它应该让你超越你在这里遇到的特殊问题。

答案 1 :(得分:2)

您正在尝试子类化不属于子类的类型。这要求您以两种不同的方式依赖其实现的内部结构(其中一种可以说是stdlib中的一个错误,但另一种方式不是)。这不是必要的。

如果实际类型隐藏在封面下,则实际上没有代码可以指望您成为正式的子类型;只要你把鸭子打成队列,你就没事了。您可以通过委派给成员来做到这一点:

class InputJobQueue(object):
    def __init__(self, max_size):
        self._jq = multiprocessing.JoinableQueue(0)
        self._max_size = max_size
        self._skipped_job_count = 0
    def __getattr__(self, name):
        return getattr(self._jq, name)
    # your overrides/new methods

(显式委托JoinableQueue的文档化方法而不是__getattr__ - 委托所有内容可能更清晰,但为了简洁起见,我做了更短的版本。)

构造函数是函数还是类是不重要的,因为你唯一要做的就是调用它。实际类型如何被腌制并不重要,因为一个类只负责识别其成员,而不知道如何腌制它们。你的所有问题都消失了。