Leçon 19 - Programmation Asynchrone

35 minutes Avancé P4 - Concepts avancés

Maîtrisez async/await pour créer des applications qui ne se bloquent pas pendant les opérations longues.

Qu'est-ce que l'asynchrone ?

L'asynchrone permet de faire des tâches longues (téléchargement, requêtes réseau) sans bloquer votre programme. C'est comme commander au restaurant : vous ne restez pas debout à attendre, vous vous asseyez et le serveur vous apporte le plat quand il est prêt.

💡 Deux mots-clés essentiels :
  • async : Marque une fonction comme asynchrone
  • await : Attend le résultat sans bloquer

Exemple simple : Téléchargement

Comparaison entre synchrone (bloquant) et asynchrone (non-bloquant) :

C#
// ❌ Version synchrone - BLOQUE tout static void TelechargerSync() { Console.WriteLine("Début téléchargement..."); Thread.Sleep(3000); // BLOQUE pendant 3 secondes Console.WriteLine("Téléchargement terminé"); } // ✅ Version asynchrone - NE BLOQUE PAS static async Task TelechargerAsync() { Console.WriteLine("Début téléchargement..."); await Task.Delay(3000); // N'bloque PAS Console.WriteLine("Téléchargement terminé"); } // Utilisation static async Task Main() { Console.WriteLine("Application démarrée"); // Lance le téléchargement sans attendre Task tache = TelechargerAsync(); // On peut faire autre chose en attendant! Console.WriteLine("Je fais autre chose..."); // Attendre que ça finisse await tache; Console.WriteLine("Tout est terminé"); }

Retourner une valeur

Les fonctions async peuvent retourner des résultats :

C#
// Fonction async qui retourne un nombre static async Task<int> CalculerAsync(int a, int b) { await Task.Delay(1000); // Simule un calcul long return a + b; } // Fonction async qui retourne un texte static async Task<string> TelechargerTexteAsync(string url) { await Task.Delay(2000); // Simule téléchargement return $"Contenu de {url}"; } // Utilisation static async Task Main() { int résultat = await CalculerAsync(5, 3); Console.WriteLine($"Résultat: {résultat}"); // 8 string texte = await TelechargerTexteAsync("https://example.com"); Console.WriteLine(texte); }

Exécuter plusieurs tâches en parallèle

Lancer plusieurs opérations en même temps pour gagner du temps :

C#
static async Task<string> TelechargerFichierAsync(string nom) { Console.WriteLine($"📥 Téléchargement de {nom}..."); await Task.Delay(2000); Console.WriteLine($"✅ {nom} téléchargé"); return $"Contenu de {nom}"; } static async Task ExempleParallele() { var chrono = System.Diagnostics.Stopwatch.StartNew(); // ❌ Séquentiel : une après l'autre (lent) await TelechargerFichierAsync("fichier1.txt"); await TelechargerFichierAsync("fichier2.txt"); await TelechargerFichierAsync("fichier3.txt"); // Temps total: ~6 secondes Console.WriteLine($"Séquentiel: {chrono.ElapsedMilliseconds}ms\n"); // ✅ Parallèle : tout en même temps (rapide) chrono.Restart(); Task<string> tache1 = TelechargerFichierAsync("fichier1.txt"); Task<string> tache2 = TelechargerFichierAsync("fichier2.txt"); Task<string> tache3 = TelechargerFichierAsync("fichier3.txt"); // Attendre que TOUTES se terminent string[] résultats = await Task.WhenAll(tache1, tache2, tache3); // Temps total: ~2 secondes! Console.WriteLine($"Parallèle: {chrono.ElapsedMilliseconds}ms"); }

Gérer les erreurs

Utilisez try-catch avec async/await :

C#
static async Task<string> OperationRisqueeAsync(bool causerErreur) { await Task.Delay(1000); if (causerErreur) { throw new Exception("Oups, une erreur !"); } return "Succès"; } static async Task TesterErreurs() { // Gérer une erreur try { string résultat = await OperationRisqueeAsync(true); Console.WriteLine($"✅ {résultat}"); } catch (Exception ex) { Console.WriteLine($"❌ Erreur: {ex.Message}"); } // Sans erreur try { string résultat = await OperationRisqueeAsync(false); Console.WriteLine($"✅ {résultat}"); } catch (Exception ex) { Console.WriteLine($"❌ Erreur: {ex.Message}"); } }

Timeout et annulation

Annuler une opération qui prend trop de temps :

C#
static async Task OperationLongueAsync(CancellationToken token) { for (int i = 1; i <= 10; i++) { // Vérifier si annulation demandée token.ThrowIfCancellationRequested(); Console.WriteLine($"Étape {i}/10"); await Task.Delay(500, token); } Console.WriteLine("✅ Opération terminée"); } static async Task TesterTimeout() { // Créer un timeout de 3 secondes using var cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromSeconds(3)); try { await OperationLongueAsync(cts.Token); } catch (OperationCanceledException) { Console.WriteLine("⏰ Timeout! Opération annulée après 3 secondes"); } }
⚡ Règles importantes :
  • Toujours utiliser await sur les Task (pas .Result ou .Wait())
  • async/await tout le chemin jusqu'au Main()
  • Task.WhenAll pour exécuter en parallèle
  • CancellationToken pour pouvoir annuler
  • try-catch pour gérer les erreurs

Exercice pratique

Créez un simulateur d'API qui télécharge des données utilisateur en parallèle :