web-dev-qa-db-fra.com

Remplir une file d'attente et gérer le multitraitement dans python

J'ai ce problème en python:

  • J'ai une file d'URL que je dois vérifier de temps en temps
  • si la file d'attente est remplie, je dois traiter chaque élément de la file d'attente
  • Chaque élément de la file d'attente doit être traité par un seul processus (multiprocessing)

Jusqu'à présent, j'ai réussi à réaliser cela "manuellement" comme ceci:

while 1:
        self.updateQueue()

        while not self.mainUrlQueue.empty():
            domain = self.mainUrlQueue.get()

            # if we didn't launched any process yet, we need to do so
            if len(self.jobs) < maxprocess:
                self.startJob(domain)
                #time.sleep(1)
            else:
                # If we already have process started we need to clear the old process in our pool and start new ones
                jobdone = 0

                # We circle through each of the process, until we find one free ; only then leave the loop 
                while jobdone == 0:
                    for p in self.jobs :
                        #print "entering loop"
                        # if the process finished
                        if not p.is_alive() and jobdone == 0:
                            #print str(p.pid) + " job dead, starting new one"
                            self.jobs.remove(p)
                            self.startJob(domain)
                            jobdone = 1

Cependant, cela entraîne des tonnes de problèmes et d'erreurs. Je me demandais si je n'étais pas mieux adapté à l'utilisation d'un pool de processus. Quelle serait la bonne façon de procéder?

Cependant, la file d'attente est souvent vide et peut être remplie par 300 éléments en une seconde, donc je ne sais pas trop comment faire les choses ici.

17
Tibo

Vous pouvez utiliser les capacités de blocage de queue pour générer plusieurs processus au démarrage (en utilisant multiprocessing.Pool ) et les laisser dormir jusqu'à ce que certaines données soient disponibles dans la file d'attente à traiter. Si vous n'êtes pas familier avec cela, vous pouvez essayer de "jouer" avec ce programme simple:

import multiprocessing
import os
import time

the_queue = multiprocessing.Queue()


def worker_main(queue):
    print os.getpid(),"working"
    while True:
        item = queue.get(True)
        print os.getpid(), "got", item
        time.sleep(1) # simulate a "long" operation

the_pool = multiprocessing.Pool(3, worker_main,(the_queue,))
#                            don't forget the coma here  ^

for i in range(5):
    the_queue.put("hello")
    the_queue.put("world")


time.sleep(10)

Testé avec Python 2.7.3 sous Linux

Cela engendrera 3 processus (en plus du processus parent). Chaque enfant exécute le worker_main fonction. Il s'agit d'une simple boucle récupérant un nouvel élément de la file d'attente à chaque itération. Les travailleurs bloqueront si rien n'est prêt à être traité.

Au démarrage, les 3 processus seront mis en veille jusqu'à ce que la file d'attente soit alimentée en données. Lorsqu'une donnée est disponible, l'un des travailleurs en attente récupère cet élément et commence à le traiter. Après cela, il essaie d'obtenir un autre élément de la file d'attente, attendant à nouveau si rien n'est disponible ...

44
Sylvain Leroux