Traitement batch multi-cœurs en Python

8 05 2009

Ce billet est le petit frère du précédent billet Traitement batch multi-cœurs en PHP.

Pourquoi Python ? Utilisant désormais Python et PHP, j’ai voulu transposé cette fonction PHP en Python. Ça peut même servir à faire une comparaison rapide entre un code PHP et un code Python.

Le code Python est effectivement plus court (36 lignes contre 52 en PHP) et plus lisible, cette dernière affirmation restant un point de vue personnel.

Utilisation

C’est uniquement une fonction que je livre ici ! Si vous voulez vous en servir, il vous faudra rajouter du code (si peu) pour lui faire faire ce que vous voulez.

Le prototype de la fonction est simple :

def pool_execute(commandes,nb_max_process)

Les paramètres sont les suivants :

  • commandes : Un tableau dont chaque entrée est une chaîne de caractères contenant une commande shell à exécuter ou une liste comme ce que propose la classe Popen du module subprocess.
  • nb_max_process : Le nombre maximum de commandes pouvant être exécutées simultanément.

Exemple d’utilisation : Conversion de PNG en JPEG sur un dual-core

commandes=[
  "convert photo1.png photo1.jpg",
  "convert photo2.png photo2.jpg",
  ["convert","photo3.png","photo3.jpg"]
]
pool_execute(commandes,2)

Plutôt simple d’utilisation, non ?

L’appel à pool_execute ne retourne que lorsque tous les processus se sont terminés. C’est à vous de vous assurer qu’aucun processus ne va se retrouver dans une situation de boucle infinie…

Explications

La fonction pool_execute utilise un pool de processus. Il s’agit d’un banal tableau dont la taille est égale au nombre maximum de commandes à exécuter.

La boucle principale va ensuite s’activer toutes les 0,05 secondes pour voir si une nouvelle commande ne peut pas être lancée.

Pour cela, elle parcourt chaque entrée du pool (qui correspond à une commande exécutée) et pour chaque entrée, elle teste si le processus associé est encore en cours d’exécution. S’il ne l’est plus, on le vire du pool pour en installer un nouveau.

Un seul lancement de commande se fait par itération, toutes les 0,05 secondes.

La seconde boucle permet d’attendre les dernières commandes encore en cours d’exécution avant de rendre la main à l’appelant.

Pool_execute fait appel à la classe Popen pour gérer les processus. La méthode poll des objets générés permet de savoir si le processus est terminé. Contrairement à la version PHP, il n’est nul besoin de fermer le processus car on travaille avec des objets qui feront le ménage à leur destruction.

Code source

Cette fonction est à incorporer à vos scripts :

from subprocess import Popen
from time import sleep

def pool_execute(commandes,nb_max_process):
  # Initialise le pool de processus
  pool=[False]*nb_max_process

  # Exécute toutes les commandes
  while len(commandes)>0:
    commande=commandes.pop(0)

    # Essaie de lancer une commande
    commande_lancee=False
    while commande_lancee==False:
      sleep(0.05)

      # Recherche une entrée libre dans le pool
      for i in range(0,nb_max_process):
        # Teste si l'entrée a déjà été utilisée ou point sur un processus terminé
        if not pool[i] or pool[i].poll()!=None:
          pool[i]=Popen(commande,shell=(type(commande)==str))
          commande_lancee=True
          break

  # Attend que toutes les commandes restantes se terminent
  commande_restante=True
  while commande_restante:
    sleep(0.05)

    # Recherche une commande encore en cours d'exécution dans le pool
    commande_restante=False
    for i in range(0,nb_max_process):
      # Teste si l'entrée pointe sur un processus terminé
      if pool[i] and pool[i].poll()==None:
        commande_restante=True
        break

Actions

Information

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s




%d blogueurs aiment cette page :