Introduction
Quand un programme Python doit exécuter plusieurs tâches lourdes ou indépendantes, il est souvent utile de les exécuter en parallèle. Le module intégré multiprocessing
permet justement d’exploiter les cœurs multiples de votre processeur, en lançant plusieurs processus qui s’exécutent en parallèle au lieu de manière séquentielle.
Contrairement au multithreading limité par le GIL (Global Interpreter Lock), le multiprocessing lance de vrais processus système, chacun avec sa propre mémoire. C’est une solution idéale pour les tâches CPU-intensives, comme le calcul scientifique, le traitement d’images ou le rendu de jeux.
Dans cet article, vous allez découvrir comment fonctionne multiprocessing
, comment créer des processus, gérer des files de communication, synchroniser les tâches, et bien plus.
1. Pourquoi utiliser multiprocessing ?
Le module multiprocessing
permet de :
- répartir des calculs gourmands sur plusieurs cœurs de CPU,
- accélérer des boucles lentes,
- exécuter plusieurs tâches indépendantes en parallèle.
Exemple d’usage : traitement de plusieurs fichiers en simultané, génération d’images, traitement de données lourdes…
2. Lancer un processus simple
Voici un exemple de base qui crée un processus parallèle :
import multiprocessing
def afficher():
print("Processus exécuté !")
if __name__ == '__main__':
p = multiprocessing.Process(target=afficher)
p.start()
p.join()
start()
lance le processus.join()
bloque jusqu’à ce que le processus soit terminé.
3. Passer des arguments à un processus
Vous pouvez transmettre des arguments à une fonction via args
:
def calcul(nom):
print(f"{nom} est en cours...")
if __name__ == '__main__':
p = multiprocessing.Process(target=calcul, args=("Tâche 1",))
p.start()
p.join()
4. Lancer plusieurs processus en boucle
Voici comment lancer plusieurs processus à la fois :
def travail(n):
print(f"Travail #{n} lancé")
if __name__ == '__main__':
processus = []
for i in range(5):
p = multiprocessing.Process(target=travail, args=(i,))
processus.append(p)
p.start()
for p in processus:
p.join()
5. Utiliser un Pool de processus
Le module propose aussi une abstraction avec Pool
pour lancer plusieurs tâches facilement :
from multiprocessing import Pool
def carre(n):
return n * n
if __name__ == '__main__':
with Pool(4) as pool:
resultats = pool.map(carre, [1, 2, 3, 4, 5])
print(resultats)
map()
applique la fonction à tous les éléments de la liste en parallèle.
6. Partager des données entre processus
Puisque chaque processus a sa propre mémoire, vous devez utiliser des structures partagées comme :
6.1. Valeur partagée (Value
)
from multiprocessing import Value
def incremente(valeur):
for _ in range(1000):
valeur.value += 1
if __name__ == '__main__':
v = Value('i', 0) # 'i' pour entier
p1 = multiprocessing.Process(target=incremente, args=(v,))
p2 = multiprocessing.Process(target=incremente, args=(v,))
p1.start()
p2.start()
p1.join()
p2.join()
print("Résultat final :", v.value)
6.2. Liste partagée (Array
)
from multiprocessing import Array
def doubler(liste):
for i in range(len(liste)):
liste[i] *= 2
if __name__ == '__main__':
arr = Array('i', [1, 2, 3, 4])
p = multiprocessing.Process(target=doubler, args=(arr,))
p.start()
p.join()
print(arr[:])
7. Communiquer avec des files (Queue
)
Utilisez Queue
pour envoyer des données d’un processus à un autre :
from multiprocessing import Queue
def producteur(q):
for i in range(5):
q.put(i)
def consommateur(q):
while not q.empty():
print("Reçu :", q.get())
if __name__ == '__main__':
q = Queue()
p1 = multiprocessing.Process(target=producteur, args=(q,))
p2 = multiprocessing.Process(target=consommateur, args=(q,))
p1.start()
p1.join()
p2.start()
p2.join()
8. Synchroniser avec des verrous (Lock
)
Pour éviter que plusieurs processus modifient une ressource en même temps, utilisez des verrous :
from multiprocessing import Lock
def affiche_message(lock, message):
with lock:
print(message)
if __name__ == '__main__':
verrou = Lock()
for i in range(3):
p = multiprocessing.Process(target=affiche_message, args=(verrou, f"Message {i}"))
p.start()
Exemple concret : traitement parallèle de données
def traitement(n):
print(f"Traitement de {n}")
return n ** 2
if __name__ == '__main__':
with Pool(processes=4) as pool:
donnees = list(range(10))
resultats = pool.map(traitement, donnees)
print("Résultats :", resultats)
10. Astuces et bonnes pratiques
- Toujours protéger le point d’entrée avec
if __name__ == '__main__'
. - Évitez de partager trop de mémoire entre processus.
- Privilégiez
Pool
pour les tâches similaires en masse. - Utilisez
Queue
ouManager
pour des échanges complexes.
Conclusion
Le module multiprocessing de Python est une solution élégante pour paralléliser vos programmes et tirer profit de tous les cœurs de votre CPU. Que ce soit pour accélérer des calculs, automatiser plusieurs tâches en simultané ou traiter de grandes quantités de données, cette bibliothèque vous permet de maîtriser le multitraitement en toute simplicité.