Méthodes clés de la programmation multiprocessing en Python

En Python, le multithreading n'exploite pas pleinement les cœurs de processeur. Pour une utilisation optimale des ressources multi-cœurs, la programmation multiprocessing est souvent nécessaire.

Le module multiprocessing simplifie grandement la création de processus parallèles. Il gère automatiquement les sous-processus, la communication, le partage de données et la synchronisation, avec des composants tels que Process, Queue, Pipe et Lock.

Classe Process

Syntaxe : Process([group[, target[, name[, args[, kwargs]]]]])

Paramètres : target désigne la fonction à exécuter, args les arguments positionnels sous forme de tuple, kwargs les arguments sous forme de dictionnaire. name est un alias, et group est raremnet utilisé.

Méthodes : is_alive(), join(timeout), run(), start(), terminate().

Attributs : authkey, daemon (doit être défini via start()), exitcode (None pendant l'exécution, -N si terminé par le signal N), name, pid. L'attribut daemon assure la terminaison automatique du processus enfant lorsque le processus parent se termine, et doit être configuré avant start().

1. Créer un processus unique

from multiprocessing import Process

def executer_tache(nom):
    print(f"{nom} a été une bonne personne")

if __name__ == "__main__":
    proc = Process(target=executer_tache, args=('alice',))
    proc.start()  # Démarre le processus

2. Lancer plusieurs prcoessus

from multiprocessing import Process
import time
import random

def activite_sportive(nom):
    print(f"{nom} aime le sport")
    time.sleep(random.randint(1, 3))

def activite_jeux(nom):
    print(f"{nom} aime les jeux vidéo")
    time.sleep(random.randint(1, 3))

if __name__ == "__main__":
    p1 = Process(target=activite_sportive, args=('bob',))
    p2 = Process(target=activite_jeux, args=('charlie',))
    p1.start()
    p2.start()

Résultat attendu :

bob aime le sport
charlie aime les jeux vidéo

3. Définir un processus sous forme de classe

from multiprocessing import Process

class MonProcessus(Process):
    def __init__(self, nom):
        super().__init__()
        self.nom = nom

    def run(self):  # Méthode appelée automatiquement par start()
        print(f"{self.nom} a été une bonne personne")

if __name__ == "__main__":
    proc = MonProcessus('alice')
    proc.start()

4. Effet de l'attribut daemon

Sans daemon :

import time
from multiprocessing import Process

def travail(nom):
    print(f"Début du travail : {time.ctime()}")
    time.sleep(2)
    print(f"Fin du travail : {time.ctime()}")

if __name__ == "__main__":
    p = Process(target=travail, args=('alice',))
    p.start()
    print("Exécution terminée ici")

Résultat : "Exécution terminée ici" s'affiche avant la fin du travail.

Avec daemon :

from multiprocessing import Process
import time

def travail(nom):
    print(f"Début du travail : {time.ctime()}")
    time.sleep(2)
    print(f"Fin du travail : {time.ctime()}")

if __name__ == "__main__":
    p = Process(target=travail, args=('alice',))
    p.daemon = True  # Se termine automatiquement avec le parent
    p.start()
    print("Exécution terminée ici")

Résultat : Seul "Exécution terminée ici" s'affiche.

Pour exécuter le travail avec daemon activé :

import time
from multiprocessing import Process

def travail(nom):
    print(f"Début du travail : {time.ctime()}")
    time.sleep(2)
    print(f"Fin du travail : {time.ctime()}")

if __name__ == "__main__":
    p = Process(target=travail, args=('alice',))
    p.daemon = True
    p.start()
    p.join()  # Attend la fin du processus
    print("Exécution terminée ici")

5. Utilisation de join()

Exemple sans join :

from multiprocessing import Process
import time
import os

def travail_prolonge(nom, duree):
    print(f"Ami de longue date : {nom}, PID {os.getpid()}")
    time.sleep(duree)
    print(f"Bon travail : {nom}")

if __name__ == "__main__":
    p1 = Process(target=travail_prolonge, args=('alice', 2))
    p2 = Process(target=travail_prolonge, args=('bob', 1))
    p3 = Process(target=travail_prolonge, args=('charlie', 3))
    p1.start()
    p2.start()
    p3.start()
    print("Exécution terminée ici")

Résultat montre une exécution non séquentielle.

Avec join séquentiel :

from multiprocessing import Process
import time
import os

def travail_prolonge(nom, duree):
    print(f"Ami de longue date : {nom}, PID {os.getpid()}")
    time.sleep(duree)
    print(f"Bon travail : {nom}")

if __name__ == "__main__":
    debut = time.time()
    p1 = Process(target=travail_prolonge, args=('alice', 2))
    p2 = Process(target=travail_prolonge, args=('bob', 1))
    p3 = Process(target=travail_prolonge, args=('charlie', 3))
    p1.start()
    p1.join()
    p2.start()
    p2.join()
    p3.start()
    p3.join()
    print("Exécution terminée ici")
    print(f"Temps écoulé : {time.time() - debut}")

Avec join parallèle :

from multiprocessing import Process
import time
import os

def travail_prolonge(nom, duree):
    print(f"Ami de longue date : {nom}, PID {os.getpid()}")
    time.sleep(duree)
    print(f"Bon travail : {nom}")

if __name__ == "__main__":
    debut = time.time()
    p1 = Process(target=travail_prolonge, args=('alice', 2))
    p2 = Process(target=travail_prolonge, args=('bob', 1))
    p3 = Process(target=travail_prolonge, args=('charlie', 3))
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()
    print("Exécution terminée ici")
    print(f"Temps écoulé : {time.time() - debut}")

6. Autres attributs et méthodes

Exemple avec terminate :

from multiprocessing import Process
import time

def travail(nom):
    print(f"Début du travail : {time.ctime()}")
    time.sleep(2)
    print(f"Fin du travail : {time.ctime()}")

if __name__ == "__main__":
    p = Process(target=travail, args=('alice',))
    p.start()
    p.terminate()  # Termine brutalement le processus

Exemple d'accès aux attributs :

from multiprocessing import Process
import time

def travail(nom):
    print(f"Début du travail : {time.ctime()}")
    time.sleep(2)
    print(f"Fin du travail : {time.ctime()}")

if __name__ == "__main__":
    p = Process(target=travail, args=('alice',))
    print(p.is_alive())  # False avant démarrage
    p.start()
    print(p.name)       # Nom du processus
    print(p.pid)        # ID du processus
    print(p.is_alive()) # True pendant l'exécution

Étiquettes: Python multiprocessing processus daemon Concurrence

Publié le 18 juin à 06h00