web-dev-qa-db-fra.com

Comment utiliser la file d'attente de multitraitement en Python?

J'ai beaucoup de difficulté à comprendre le fonctionnement de la file d'attente de multitraitement sur python et comment l'implémenter. Disons que j'ai deux python modules d'accès Pour les données d'un fichier partagé, appelons ces deux modules un rédacteur et un lecteur. Mon plan est de faire en sorte que le lecteur et le rédacteur placent les demandes dans deux files d'attente de multitraitement distinctes, puis qu'un troisième processus mette ces demandes en boucle et les exécute en tant que tel.

Mon problème principal est que je ne sais vraiment pas comment implémenter correctement multiprocessing.queue, vous ne pouvez pas vraiment instancier l'objet pour chaque processus car il s'agira de files d'attente séparées, comment vous assurer que tous les processus sont liés à une file d'attente partagée (ou dans ce cas, les files d'attente)

64
jab

Mon problème principal est que je ne sais vraiment pas comment implémenter correctement multiprocessing.queue, vous ne pouvez pas vraiment instancier l'objet pour chaque processus car il s'agira de files d'attente séparées, comment vous assurer que tous les processus sont liés à une file d'attente partagée (ou dans ce cas, les files d'attente)

Voici un exemple simple de lecteur et d’écrivain partageant une seule file d’attente ... L’écrivain envoie au lecteur une série d’entiers; lorsque l'écrivain est à court de chiffres, il envoie "DONE", ce qui permet au lecteur de sortir de la boucle de lecture.

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

dans "from queue import Queue "il n’existe pas de module appelé queue, mais plutôt multiprocessing. Par conséquent, il devrait ressembler à" from multiprocessing import Queue "

7
Jean

Voici une utilisation simple morte de multiprocessing.Queue et multiprocessing.Process qui permet aux appelants d'envoyer un "événement" et des arguments à un processus séparé qui envoie l'événement à une méthode "do_" du processus. (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)

Usage:

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

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

Le send se produit dans le processus parent, le do_* se produit dans le processus enfant.

J'ai laissé de côté toute gestion des exceptions qui interromprait évidemment la boucle d'exécution et quittait le processus enfant. Vous pouvez également le personnaliser en remplaçant run pour contrôler le blocage ou autre chose.

Cela n’est vraiment utile que dans les cas où vous n’avez qu’un seul processus de travail, mais j’estime que c’est une réponse pertinente à cette question pour illustrer un scénario courant avec un peu plus d’orientation objet.

0
Joe Holloway