[英]How to inherit from a multiprocessing queue?
使用以下代码,似乎传递给worker的队列实例未初始化:
from multiprocessing import Process
from multiprocessing.queues import Queue
class MyQueue(Queue):
def __init__(self, name):
Queue.__init__(self)
self.name = name
def worker(queue):
print queue.name
if __name__ == "__main__":
queue = MyQueue("My Queue")
p = Process(target=worker, args=(queue,))
p.start()
p.join()
抛出:
... line 14, in worker
print queue.name
AttributeError: 'MyQueue' object has no attribute 'name'
我无法重新初始化队列,因为我将丢失queue.name的原始值,甚至将队列的名称作为参数传递给worker(这应该可行,但它不是一个干净的解决方案)。
那么,如何从multiprocessing.queues.Queue继承而不会出现此错误?
在POSIX上,通过简单继承将Queue
对象共享给子进程。*
在Windows上,这是不可能的,所以它必须挑选Queue
,通过管道将其发送给孩子,并取消它。
(这可能不是很明显,因为如果你实际上试图RuntimeError: MyQueue objects should only be shared between processes through inheritance
一个Queue
,你会得到一个异常, RuntimeError: MyQueue objects should only be shared between processes through inheritance
。如果你查看源代码,你会看到这是真的谎言 - 如果你在multiprocess
进程没有产生子进程的过程中尝试挑选一个Queue
,它只会引发这个异常。)
当然,通用的pickle和unpickling不会有任何好处,因为你最终会得到两个相同的队列,而不是两个进程中的相同队列。 因此, multiprocessing
通过为unpickling中使用的对象添加register_after_fork
机制来扩展一些内容。**如果查看Queue
的源代码 ,您可以看到它是如何工作的。
但你真的不需要知道它是如何起作用的; 你可以像任何其他类的酸洗一样挂钩它。 例如,这应该工作:***
def __getstate__(self):
return self.name, super(MyQueue, self).__getstate__()
def __setstate__(self, state):
self.name, state = state
super(MyQueue, self).__setstate__(state)
有关详细信息, pickle
文档解释了影响课程腌制方式的不同方法。
(如果它不工作,我还没有做出愚蠢的错误...那么你必须知道至少有一点它是如何工作挂钩...但最有可能只是弄清楚之前,是否做你的额外的工作或者在_after_fork()
之后, _after_fork()
需要交换最后两行...)
*我不确定它实际上保证在POSIX平台上使用简单的fork继承。 在2.7和3.3上恰好是这样。 但是有一个multiprocessing
的分支,它使用Windows风格的pickle-所有平台上的所有内容保持一致性,另一个使用OS X上的混合允许在单线程模式下使用CoreFoundation
,或类似的东西,它显然是可行的那样。
**实际上,我认为 Queue
只是为了方便而使用register_after_fork
,并且可以在没有它的情况下进行重写......但这取决于Pipe
在Windows上的_after_fork
或者POSIX上的Lock
和BoundedSemaphore
所做的魔术。
***这只是正确的,因为我碰巧知道,从阅读源代码, Queue
是一个新式的类,不会覆盖__reduce__
或__reduce_ex
,并且永远不会从__getstate__
返回falsey值。 如果您不知道,那么您必须编写更多代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.