Python 如何子类化multiprocessing.JoinableQueue

Python 如何子类化multiprocessing.JoinableQueue,python,multithreading,multiprocessing,Python,Multithreading,Multiprocessing,我正在尝试子类化多处理.JoinableQueue,以便跟踪跳过而不是完成的作业。我正在使用JoinableQueue将作业传递给一组多处理.Process,我有一个线程.Thread填充队列。以下是我的实现尝试: import multiprocessing class InputJobQueue(multiprocessing.JoinableQueue): def __init__(self, max_size): super(InputJobQueue, se

我正在尝试子类化
多处理.JoinableQueue
,以便跟踪跳过而不是完成的作业。我正在使用JoinableQueue将作业传递给一组
多处理.Process
,我有一个
线程.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()
但是,我遇到了以下问题:

查看
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

对于
多处理
,像
JoinableQueue
这样的对象在进程之间神奇地共享的方式是显式共享核心同步对象,并酸洗“包装器”材料以通过管道

如果您了解酸洗的工作原理,您可以查看源代码以了解它使用的是
\uuuu getstate\uuuu
/
\uuuu setstate\uuuu
。因此,您只需覆盖这些属性即可添加自己的属性。大概是这样的:

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]

我不保证这会真正起作用,因为很明显这些类不是被设计成子类的(针对您引用的bug的建议修复方法是记录这些类不能被子类化,并找到一种使错误消息更好的方法…)。但是它应该可以帮助您克服这里遇到的特定问题。

您试图对一个不应该被子类化的类型进行子类化。这要求您以两种不同的方式依赖于其实现的内部(其中一种可能是stdlib中的bug,但另一种不是)。这是没有必要的

如果实际类型隐藏在封面下,那么没有代码可以期望您成为正式的子类型;只要你能像队列一样排队,你就没事了。您可以通过授权给成员来执行以下操作:

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
的文档化方法可能比委托
\uuu getattr\uuuu
更简洁,但为了简洁起见,我选择了较短的版本。)


不管该构造函数是函数还是类,因为您所做的唯一事情就是调用它。实际类型的pickle方式无关紧要,因为类只负责标识其成员,而不知道如何对其进行pickle。所有的问题都消失了。

顺便说一句,IIRC,3.2+
多处理中修复的一个关键错误是继承队列的进程并不总是正常工作。我认为PyPI上有一个3.2(或更高版本?
多处理
的后端口可以解决这个问题;您可能需要安装它(并查看包装器函数的源代码,以了解如何获取上下文对象并将其传递给实际的队列对象)。但我不认为这是你的问题。实际上,看起来后端口已经被取代了,所以使用它而不是搜索后端口。错误报告只是说应该更清楚,顶级
多处理
模块中的
JoinableQueue
是一个函数,而不是一个类,真正的类在
多处理队列中。对实际的
队列
对象进行子类化可以很好地工作,只要您正确地处理pickle/unpickle(您的答案涵盖了这一点)。@dano:对要进行子类化的文档类型进行子类化不需要了解其实现的内部结构。没有办法知道
JoinableQueue
碰巧使用
\uuuu setstate\uuuu
机制进行酸洗而不读取源代码,也没有理由期望在Python 3.5中它不会改变;
Queue
实现
\uu getstate\uuu
的方式清楚地表明它不是(尽管
JoinableQueue
Queue
的一个子类)。我只是说你关于bug报告的这句话不太准确:“你所引用的bug的建议修复是记录类不能被子类化”。至少不是基于bug报告中实际编写的任何内容。报告只是建议记录您需要
导入multiprocessing.queues.JoinableQueue
,以便子类化工作。fwiw我同意委派是更好的选择。我一直致力于将
多处理
类与
asyncio
集成在一起,而对所有这些对象进行正确的子分类被证明是非常麻烦的。
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