Programmation asynchrone en C# : guide complet en pratique
La programmation asynchrone est l'un des concepts clés du développement moderne en C# et sur la plateforme .NET. Elle permet de créer des applications réactives qui ne bloquent pas le thread d'exécution lors de l'attente d'opérations longues : lecture de fichiers, requêtes à une base de données, appels HTTP. Dans ce guide, nous analyserons le fonctionnement de l'asynchronisme en C# à l'aide d'exemples pratiques utilisant les mots-clés async et await, ainsi que les meilleures pratiques.
Qu'est-ce que la programmation asynchrone et pourquoi en a-t-on besoin ?
En programmation synchrone, chaque opération s'exécute séquentiellement. Si une méthode appelle, par exemple, le chargement de données depuis le réseau, le thread d'exécution est bloqué jusqu'à la fin de cette opération. Cela entraîne le « gel » de l'interface dans les applications de bureau ou une utilisation inefficace des ressources du serveur dans les applications web.
La programmation asynchrone résout ce problème : le thread n'est pas bloqué, mais retourne dans le pool de threads pour traiter d'autres tâches. Lorsque l'opération se termine, l'exécution reprend là où elle a été interrompue.
Les principaux avantages de l'asynchronisme en C# :
- Réactivité de l'interface utilisateur — l'application ne se fige pas lors d'opérations longues.
- Scalabilité des serveurs — un seul thread peut gérer de nombreuses requêtes.
- Utilisation efficace des ressources — moins de temps d'inactivité des threads.
Les bases de async et await en C#
Les mots-clés async et await sont du sucre syntaxique qui simplifie le travail avec les opérations asynchrones. Regardons un exemple de base :
using System;using System.Net.Http;using System.Threading.Tasks;
public class AsyncExample{ public async Task<string> DownloadDataAsync(string url) { using (var client = new HttpClient()) { // await ne bloque pas le thread string result = await client.GetStringAsync(url); return result; } }
public async Task RunAsync() { Console.WriteLine("Début du téléchargement..."); string data = await DownloadDataAsync("https://api.example.com/data"); Console.WriteLine($"Téléchargé : {data.Length} caractères"); }}Explication du code :
- La méthode est marquée
async— cela permet l'utilisation deawaità l'intérieur. - Le type de retour est
Task<string>(ou simplementTaskpour les méthodes void). awaitsuspend l'exécution de la méthode jusqu'à l'obtention du résultat, mais ne bloque pas le thread.
Important : La méthode Main dans une application console C# 7.1+ peut également être asynchrone :
static async Task Main(string[] args){ var example = new AsyncExample(); await example.RunAsync();}Travailler avec Task et Task<T>
Le type Task représente une opération asynchrone. Il peut se trouver dans les états : en attente (Pending), en cours d'exécution (Running), terminé (Completed), avec erreur (Faulted) ou annulé (Canceled).
Regardons la création et l'exécution manuelles de tâches :
public async Task ProcessDataAsync(){ // Créons une tâche qui s'exécute dans le pool de threads Task<int> task = Task.Run(() => { // Simulation d'un travail long Task.Delay(2000).Wait(); return 42; });
// Attendons le résultat int result = await task; Console.WriteLine($"Résultat : {result}");}Pour l'exécution parallèle de plusieurs tâches, utilisez Task.WhenAll :
public async Task DownloadMultipleAsync(){ var urls = new[] { "https://site1.com", "https://site2.com", "https://site3.com" }; var tasks =