Le module multiprocessing en Python offre une boîte à outils puissante pour créer des programmes parallèles capables d'exploiter efficacement les processeurs multicœurs. Contrairement au multithreading standard, limité par le Global Interpreter Lock (GIL), multiprocessing permet d'exécuter plusieurs processus simultanément, chacun disposant de sa propre mémoire et d'une exécution indépendante.
Principes fondamentaux du multiprocessing
La multiprocessus en Python repose sur la création de processus distincts pouvant s'exécuter en parallèle sur différents cœurs du processeur. Chaque processus fonctionne dans un espace mémoire isolé, éliminant ainsi les problèmes de données partagées typiques du multithreading.
Les composants clés du module multiprocessing incluent :
- Process — classe pour créer et gérer des processus individuels
- Pool — pool de processus pour exécuter efficacement de nombreuses tâches
- Queue — files d'attente pour un transfert sécurisé de données entre processus
- Lock — mécanismes de synchronisation pour contrôler l'accès aux ressources
- Manager — objets pour gérer les données partagées
Quand utiliser multiprocessing
Multiprocessing est particulièrement efficace dans les cas suivants :
Tâches intensives en CPU : calculs mathématiques, traitement d'images, analyse de données, simulations scientifiques. Ces tâches bénéficient grandement d'une exécution parallèle sur différents cœurs.
Traitement de grands volumes de données : lorsque vous devez appliquer la même fonction à de nombreux éléments, multiprocessing peut accélérer considérablement l'exécution.
Tâches indépendantes : opérations qui ne nécessitent pas d'échanges fréquents de données entre processus.
Pour les tâches intensives en I/O (fichiers, requêtes réseau), privilégiez la programmation asynchrone (asyncio) ou le multithreading.
Création et gestion des processus
Exemple de base avec la classe Process
import multiprocessing
import time
def worker_task(name, duration):
"""Fonction exécutée dans un processus séparé"""
print(f"Le processus {name} a commencé")
time.sleep(duration)
print(f"Le processus {name} est terminé")
if __name__ == "__main__":
# Création des processus
process1 = multiprocessing.Process(target=worker_task, args=("Worker-1", 3))
process2 = multiprocessing.Process(target=worker_task, args=("Worker-2", 2))
# Lancement des processus
start_time = time.time()
process1.start()
process2.start()
# Attente de la fin des processus
process1.join()
process2.join()
end_time = time.time()
print(f"Temps d'exécution total : {end_time - start_time:.2f} secondes")
Héritage de la classe Process
import multiprocessing
import os
import time
class CustomProcess(multiprocessing.Process):
def __init__(self, name, work_count):
super().__init__()
self.name = name
self.work_count = work_count
def run(self):
"""Méthode exécutée dans le processus"""
print(f"Processus {self.name} (PID : {os.getpid()}) a commencé")
for i in range(self.work_count):
print(f"{self.name} : exécution de la tâche {i+1}")
time.sleep(1)
print(f"Processus {self.name} terminé")
if __name__ == "__main__":
processes = []
# Création de plusieurs processus
for i in range(3):
p = CustomProcess(f"Process-{i+1}", 3)
processes.append(p)
p.start()
# Attente de la fin de tous les processus
for p in processes:
p.join()
Travailler avec un pool de processus
Pool offre une interface pratique pour gérer