web-dev-qa-db-ja.com

Pythonでマルチプロセッシングキューを使用する方法は?

マルチプロセッシングキューがpythonでどのように機能するか、およびそれをどのように実装するかを理解しようとすると、多くの問題が発生します。共有ファイルのデータにアクセスする2つのpythonモジュールがあるとします。これら2つのモジュールをライターとリーダーと呼びましょう。私の計画では、リーダーとライターの両方にリクエストを2つの別々のマルチプロセッシングキューに入れてから、3番目のプロセスにこれらのリクエストをループでポップさせて実行します。

私の主な問題は、multiprocessing.queueを正しく実装する方法が本当にわからないことです。各プロセスは個別のキューになるため、各プロセスのオブジェクトを実際にインスタンス化することはできません。この場合、キュー)

64
jab

私の主な問題は、multiprocessing.queueを正しく実装する方法が本当にわからないことです。各プロセスは個別のキューになるため、各プロセスのオブジェクトを実際にインスタンス化することはできません。この場合、キュー)

これは、単一のキューを共有するリーダーとライターの簡単な例です...ライターは整数の束をリーダーに送信します。ライターが数字を使い果たすと、「DONE」を送信します。これにより、リーダーは読み取りループから抜け出すことができます。

from multiprocessing import Process, Queue
import time
import sys

def reader_proc(queue):
    ## Read from the queue; this will be spawned as a separate Process
    while True:
        msg = queue.get()         # Read from the queue and do nothing
        if (msg == 'DONE'):
            break

def writer(count, queue):
    ## Write to the queue
    for ii in range(0, count):
        queue.put(ii)             # Write 'count' numbers into the queue
    queue.put('DONE')

if __name__=='__main__':
    pqueue = Queue() # writer() writes to pqueue from _this_ process
    for count in [10**4, 10**5, 10**6]:             
        ### reader_proc() reads from pqueue as a separate process
        reader_p = Process(target=reader_proc, args=((pqueue),))
        reader_p.daemon = True
        reader_p.start()        # Launch reader_proc() as a separate python process

        _start = time.time()
        writer(count, pqueue)    # Send a lot of stuff to reader()
        reader_p.join()         # Wait for the reader to finish
        print("Sending {0} numbers to Queue() took {1} seconds".format(count, 
            (time.time() - _start)))
87
Mike Pennington

from queue import Queue」にはqueueというモジュールはありません。代わりにmultiprocessingを使用する必要があります。したがって、「from multiprocessing import Queue」のようになります

7
Jean

multiprocessing.Queuemultiprocessing.Processの簡単な使用法は、呼び出し元が「イベント」と引数をプロセスの「do_」メソッドにディスパッチする別のプロセスに送信できるようにします。 (Python 3.4以降)

import multiprocessing as mp
import collections

Msg = collections.namedtuple('Msg', ['event', 'args'])

class BaseProcess(mp.Process):
    """A process backed by an internal queue for simple one-way message passing.
    """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.queue = mp.Queue()

    def send(self, event, *args):
        """Puts the event and args as a `Msg` on the queue
        """
       msg = Msg(event, args)
       self.queue.put(msg)

    def dispatch(self, msg):
        event, args = msg

        handler = getattr(self, "do_%s" % event, None)
        if not handler:
            raise NotImplementedError("Process has no handler for [%s]" % event)

        handler(*args)

    def run(self):
        while True:
            msg = self.queue.get()
            self.dispatch(msg)

使用法:

class MyProcess(BaseProcess):
    def do_helloworld(self, arg1, arg2):
        print(arg1, arg2)

if __== "__main__":
    process = MyProcess()
    process.start()
    process.send('helloworld', 'hello', 'world')

sendは親プロセスで発生し、do_*は子プロセスで発生します。

明らかに、実行ループを中断して子プロセスを終了する例外処理は省略しました。 runをオーバーライドして、ブロッキングなどを制御することでカスタマイズすることもできます。

これは、ワーカープロセスが1つしかない状況でのみ本当に役立ちますが、もう少しオブジェクト指向の一般的なシナリオを示すのは、この質問に対する適切な答えだと思います。

0
Joe Holloway