first comit

This commit is contained in:
Johan
2025-12-15 15:50:40 +01:00
commit a4144d28b3
15 changed files with 1500 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
import logging
import sys
import time
# --- Configuration ---
NUM_TASKS = 15
SLEEP_DURATION = 0.2 # Chaque tâche "attendra" 0.2 seconde
# --- Fonctions ---
def setup_logging():
"""Configure un logging simple pour la sortie console."""
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler(sys.stdout)],
)
def worker_task(task_id: int):
"""
Une fonction qui simule un travail bloquant (ex: une longue requête réseau).
time.sleep() gèle le thread et bloque l'exécution de tout autre code.
"""
logging.info(f"Tâche {task_id}: Démarrage...")
time.sleep(SLEEP_DURATION)
logging.info(f"Tâche {task_id}: Terminée.")
return f"Résultat de la tâche {task_id}"
def main():
"""Fonction principale du script synchrone."""
setup_logging()
logging.info("--- DÉMARRAGE DE LA SIMULATION SYNCHRONE ---")
start_time = time.perf_counter()
# Les tâches sont exécutées l'une après l'autre.
# La suivante ne commence que lorsque la précédente est terminée.
results = [worker_task(i) for i in range(NUM_TASKS)]
duration = time.perf_counter() - start_time
logging.info("-" * 50)
logging.info(f"Exécution SYNCHRONE terminée en {duration:.2f} secondes.")
expected_time = NUM_TASKS * SLEEP_DURATION
logging.info(f"Temps attendu : {NUM_TASKS} tâches * {SLEEP_DURATION}s = {expected_time:.2f}s.")
logging.info("Les temps d'attente se sont additionnés.")
logging.info("-" * 50)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,54 @@
import logging
import sys
import time
# --- Configuration ---
NUM_TASKS = 15
SLEEP_DURATION = 0.2 # Chaque tâche "attendra" 0.2 seconde
# --- Fonctions ---
def setup_logging():
"""Configure un logging simple pour la sortie console."""
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler(sys.stdout)],
)
def worker_task(task_id: int):
"""
Une fonction qui simule un travail bloquant (ex: une longue requête réseau).
time.sleep() gèle le thread et bloque l'exécution de tout autre code.
"""
logging.info(f"Tâche {task_id}: Démarrage...")
time.sleep(SLEEP_DURATION)
logging.info(f"Tâche {task_id}: Terminée.")
return f"Résultat de la tâche {task_id}"
def main():
"""Fonction principale du script synchrone."""
setup_logging()
logging.info("--- DÉMARRAGE DE LA SIMULATION SYNCHRONE ---")
start_time = time.perf_counter()
# Les tâches sont exécutées l'une après l'autre.
# La suivante ne commence que lorsque la précédente est terminée.
results = [worker_task(i) for i in range(NUM_TASKS)]
duration = time.perf_counter() - start_time
logging.info("-" * 50)
logging.info(f"Exécution SYNCHRONE terminée en {duration:.2f} secondes.")
expected_time = NUM_TASKS * SLEEP_DURATION
logging.info(f"Temps attendu : {NUM_TASKS} tâches * {SLEEP_DURATION}s = {expected_time:.2f}s.")
logging.info("Les temps d'attente se sont additionnés.")
logging.info("-" * 50)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,56 @@
import asyncio
import logging
import sys
import time
# --- Configuration ---
NUM_TASKS = 15
SLEEP_DURATION = 0.2 # Chaque tâche "attendra" 0.2 seconde
# --- Fonctions ---
def setup_logging():
"""Configure un logging simple pour la sortie console."""
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler(sys.stdout)],
)
# TODO 1 : remplacer "def" par "async def"
def worker_task_async(task_id: int):
"""
Une coroutine qui simule un travail non-bloquant.
await asyncio.sleep() ne gèle pas le programme. Il notifie la boucle
d'événements qu'elle peut exécuter autre chose pendant cette pause.
"""
logging.info(f"Tâche {task_id}: Démarrage...")
# TODO 2 : remplacer "time.sleep" par "await asyncio.sleep"
logging.info(f"Tâche {task_id}: Terminée.")
return f"Résultat de la tâche {task_id}"
async def main():
"""Fonction principale (coroutine) du script asynchrone."""
setup_logging()
logging.info("--- DÉMARRAGE DE LA SIMULATION ASYNCHRONE ---")
start_time = time.perf_counter()
# TODO 3 : créer une liste de tâches en appelant worker_task_async, puis utiliser asyncio.gather
duration = time.perf_counter() - start_time
logging.info("-" * 50)
logging.info(f"Exécution ASYNCHRONE terminée en {duration:.2f} secondes.")
logging.info(f"Temps attendu : proche de la durée d'une seule tâche ({SLEEP_DURATION}s).")
logging.info("Les temps d'attente ont été gérés en parallèle.")
logging.info("-" * 50)
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -0,0 +1,105 @@
import logging
import multiprocessing
import sys
import time
from concurrent.futures import ProcessPoolExecutor
from typing import List, Tuple, Any, Callable
# --- CONFIGURATION ---
# Le nombre de tâches de calcul à simuler.
# Augmentez ce nombre pour mieux voir la différence de performance.
NUM_TASKS = 20
# --- LE WORKER (la tâche CPU-Bound) ---
def heavy_analysis(args: Tuple[int, int]) -> Tuple[int, float]:
"""
Une fonction qui simule un calcul scientifique ou une analyse de données complexe.
C'est une tâche purement "CPU-bound".
Elle prend un tuple en argument pour s'aligner sur le pattern utilisé dans le TP, que vous traiterez plus tard.
Paramètres:
args (Tuple[int, int]): Un tuple contenant:
- task_id (int): L'identifiant de la tâche.
- complexity (int): Un paramètre pour faire varier la durée du calcul.
Retourne:
Tuple[int, float]: Un tuple avec l'ID de la tâche et le résultat du calcul.
"""
task_id, complexity = args
logging.info(f"Tâche {task_id}: Démarrage du calcul (complexité={complexity})...")
# Simulation d'un calcul intensif : une boucle qui fait des opérations mathématiques.
result = 0
# La limite de la boucle dépend de la complexité pour que les tâches n'aient pas toutes la même durée.
limit = 2_000_000 + (complexity * 500_000)
for i in range(limit):
result += (i ** 0.5) / (i + 1) # Opération mathématique arbitraire
logging.info(f"Tâche {task_id}: Calcul terminé.")
return (task_id, result)
# --- LES LANCEURS ---
def run_sequential(worker_function: Callable, tasks: List[Any]) -> float:
"""Exécute les tâches de manière séquentielle."""
logging.info("--- DÉMARRAGE DU MODE SÉQUENTIEL ---")
start_time = time.perf_counter()
results = [worker_function(task) for task in tasks]
duration = time.perf_counter() - start_time
logging.info(f"--- MODE SÉQUENTIEL terminé en {duration:.2f} secondes. ---\n")
return duration
def run_parallel(worker_function: Callable, tasks: List[Any]) -> float:
"""Exécute les tâches en parallèle en utilisant tous les cœurs CPU disponibles."""
# On utilise tous les cœurs disponibles pour maximiser le parallélisme.
worker_count = multiprocessing.cpu_count()
logging.info(f"--- DÉMARRAGE DU MODE PARALLÈLE (avec {worker_count} processus) ---")
start_time = time.perf_counter()
# TODO 1 : instancier un ProcessPoolExecutor avec un nombre de workers donné, et en utilisant le gestionnaire de contexte `with`.
# TODO 2 : utiliser la méthode `map` de l'executor pour exécuter `worker_function` sur chaque tâche dans `tasks`.
duration = time.perf_counter() - start_time
logging.info(f"--- MODE PARALLÈLE terminé en {duration:.2f} secondes. ---\n")
return duration
# --- FONCTION PRINCIPALE ---
def main():
"""Orchestre la démonstration."""
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(processName)s - %(message)s",
handlers=[logging.StreamHandler(sys.stdout)],
)
# Création de la liste de tâches à exécuter.
# Chaque tâche est un tuple d'arguments pour notre fonction `heavy_analysis`.
# On fait varier la complexité pour simuler des données hétérogènes.
tasks_to_run = [(i, (i % 5) + 1) for i in range(NUM_TASKS)]
logging.info(f"{len(tasks_to_run)} tâches de calcul vont être lancées.")
# Lancement séquentiel
seq_duration = run_sequential(heavy_analysis, tasks_to_run)
# Lancement parallèle
par_duration = run_parallel(heavy_analysis, tasks_to_run)
# Résumé
logging.info("--- RÉSUMÉ DE LA COMPARAISON ---")
logging.info(f"Temps d'exécution séquentiel : {seq_duration:.2f}s")
logging.info(f"Temps d'exécution parallèle : {par_duration:.2f}s")
if par_duration > 0:
speedup = seq_duration / par_duration
logging.info(f"Facteur d'accélération (Speedup) : {speedup:.2f}x")
logging.info("----------------------------------")
if __name__ == "__main__":
# Nécessaire pour que multiprocessing fonctionne correctement sur certaines plateformes (Windows)
multiprocessing.freeze_support()
main()

View File