1

次のコードでは、ワーカーに渡されたキュー インスタンスが初期化されていないようです。

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 の元の値が失われるため、キューを再初期化することはできません (これは機能するはずですが、クリーンなソリューションではありません)。

では、このエラーを発生させずに multiprocessing.queues.Queue から継承するにはどうすればよいでしょうか?

4

1 に答える 1

4

POSIX では、Queueオブジェクトは単純な継承によって子プロセスに共有されます。*

Windows では、これは不可能なので、 をピクルしQueue、パイプを介して子に送信し、ピクルを解除する必要があります。

(実際に a をピクルしようとするとQueue、例外が発生するため、これは明らかではないかもしれませんRuntimeError: MyQueue objects should only be shared between processes through inheritance。ソースを調べると、これが本当に嘘であることがわかります。ピクルしようとすると、この例外が発生するだけです。 a Queuewhenmultiprocessが子プロセスの生成中でない場合。)

もちろん、2 つのプロセスで同じキューではなく、2 つの同一のキューになってしまうため、一般的な酸洗と酸洗解除は何の役にも立たないでしょう。そのため、 unpickle 時にオブジェクトが使用するメカニズムをmultiprocessing追加することで、物事を少し拡張します。**のソースを見ると、それがどのように機能するかがわかります。register_after_forkQueue

しかし、それをフックする方法を知る必要はありません。他のクラスの酸洗と同じ方法でフックできます。たとえば、これはうまくいくはずです:***

def __getstate__(self):
    return self.name, super(MyQueue, self).__getstate__()

def __setstate__(self, state):
    self.name, state = state
    super(MyQueue, self).__setstate__(state)

詳細については、pickleドキュメンテーションで、クラスの pickle 化方法に影響を与えるさまざまな方法について説明しています。

(それが機能せず、私がばかげた間違いを犯していない場合...それをフックする方法について少なくとも少しは知っておく必要があります...しかし、ほとんどの場合、事前に追加の作業を行うかどうかを判断するだけですまたは の後、_after_fork()最後の 2 行を交換するだけで済みます…)


* POSIX プラットフォームで単純な fork 継承を使用することが実際に保証されているかどうかはわかりません。これは 2.7 と 3.3 にも当てはまります。しかしmultiprocessing、一貫性のためにすべてのプラットフォームで Windows スタイルの pickle-everything を使用するフォークと、OS X でハイブリッドを使用CoreFoundationしてシングル スレッド モードなどで使用できるフォークがあり、その方法で明らかに実行可能です。 .

** 実際には、便宜上のみを使用していると思います 。それがなくても書き直すことができます... しかし、それは Windows またはPOSIXで実行される魔法に依存しています。Queueregister_after_forkPipe_after_forkLockBoundedSemaphore

*** ソースを読んでたまたまそれQueueが新しいスタイルのクラスであり、__reduce__or__reduce_exをオーバーライドせず、 から誤った値を返すことは決してないため、これは正しいだけ__getstate__です。それを知らなかったら、もっとコードを書かなければならないでしょう。

于 2013-09-19T23:52:57.213 に答える