Les Threads
Un thread (ou fil d’exécution) est l’unité d’exécution la plus petite qu’un système d’exploitation peut planifier.
-
Chaque processus peut contenir un ou plusieurs threads.
-
Tous les threads d’un même processus partagent la même mémoire et les mêmes ressources.
-
Les threads sont souvent utilisés pour exécuter plusieurs tâches concurremment dans un même programme.
Objectif
-
Accélérer l’exécution de certaines tâches.
-
Exploiter la concurrence pour améliorer la réactivité.
-
Partager facilement des données entre tâches (car mémoire commune).
-
Utiliser au mieux les temps d’attente I/O (lecture disque, requêtes réseau…).
Caractéristiques
-
Légers : moins coûteux à créer qu’un processus complet.
-
Mémoire partagée → accès direct aux mêmes variables.
-
Nécessitent synchronisation (verrous, sémaphores) pour éviter les problèmes de concurrence (race conditions).
Avantages
-
Réactivité accrue dans les programmes qui font beaucoup d’attente I/O.
-
Création rapide par rapport à un processus.
-
Partage de mémoire → pas besoin de sérialiser/désérialiser les données.
Limites
-
En Python, le GIL (Global Interpreter Lock) limite l’exécution CPU parallèle → les threads ne sont pas utiles pour les tâches CPU intensives (préférer
multiprocessing
). -
Risques de race conditions si plusieurs threads modifient la même donnée.
-
Gestion plus complexe (synchronisation, débogage difficile).
Cas d’utilisation typiques
-
Serveurs web multi-connexion.
-
Téléchargements ou traitements de fichiers en parallèle.
-
Interfaces graphiques (pour éviter que l’UI ne se fige).
-
Automatisation d’actions réseau.
Fonctions :
-
Thread (exemple)
Exemple de code :
import threading import time import random # Fonction exécutée par chaque thread def task(name, duration): print(f"{name} commence, durée prévue : {duration} secondes") time.sleep(duration) # Pause bloquante print(f"{name} terminée après {duration} secondes") # Création des threads threads = [ threading.Thread(target=task, args=("Thread 1", random.randint(1, 5))), threading.Thread(target=task, args=("Thread 2", random.randint(1, 5))), threading.Thread(target=task, args=("Thread 3", random.randint(1, 5))), ] # Démarrage des threads for t in threads: t.start() # Attente de la fin de tous les threads for t in threads: t.join() print("Tous les threads ont terminé")
Explication du code :
import threading
importe le module threading, qui permet de créer et gérer des threads pour exécuter plusieurs fonctions simultanément.import time
importe le module time pour utilisertime.sleep()
et simuler des pauses bloquantes.import random
importe le module random pour générer des durées aléatoires pour chaque thread.Définir une fonction pour les threads
def task(name, duration):
définit une fonction classique nommée task.
print(f"{name} commence, durée prévue : {duration} secondes")
affiche le début de la tâche.
time.sleep(duration)
simule une tâche longue de manière bloquante (contrairement à asyncio).
print(f"{name} terminée après {duration} secondes")
affiche la fin de la tâche.Créer des threads
threading.Thread(target=task, args=(...))
crée un thread qui exécutera la fonction task avec les arguments fournis.
Ici, trois threads sont créés, chacun avec un nom et une durée aléatoire.Démarrer les threads
t.start()
démarre le thread et lance l’exécution de sa fonction en parallèle avec les autres threads.Attendre la fin de tous les threads
t.join()
bloque le programme principal jusqu’à ce que le thread t ait terminé son exécution.
La boucle permet de s’assurer que **tous les threads sont terminés** avant de continuer.Message final
print("Tous les threads ont terminé")
affiche un message quand tous les threads ont fini leur travail.