Earn More by Sharing What You Love
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Tim Corey
38m 57s
La programmation asynchrone peut sembler décourageante en raison de sa terminologie complexe, mais elle offre des avantages significatifs en rendant les applications plus rapides et plus réactives. La vidéo de Tim Corey intitulée "C# Async / Await - Make your app more responsive and faster with asynchronous programming" fournit un guide pratique sur l'utilisation efficace de ces fonctionnalités.
Dans cet article, nous utiliserons la vidéo détaillée de Tim Corey pour décomposer ces concepts, en démontrant les applications pratiques de async et await à travers des exemples clairs. Nous couvrirons différents scénarios, des gestionnaires d'événements asynchrones à la gestion de tâches multiples, en passant par les contextes de synchronisation, la gestion des erreurs et les pièges courants tels que l'utilisation de méthodes asynchrones nulles (async void). À la fin de cet article, vous aurez une solide compréhension de la programmation asynchrone et de la manière de la mettre en œuvre dans vos propres applications C#.
La programmation asynchrone en C# est essentielle pour améliorer les performances des applications, notamment lorsqu'il s'agit d'opérations liées aux E/S ou au processeur. Les mots-clés async et await permettent aux développeurs d'écrire du code asynchrone pouvant exécuter des tâches longues sans bloquer le thread principal. En marquant une méthode avec le mot-clé async, vous indiquez que la méthode effectuera une opération asynchrone, renvoyant une tâche ou Task<t>. Le mot-clé await est utilisé dans une méthode async pour suspendre l'exécution jusqu'à ce que la tâche en attente soit terminée, permettant à d'autres opérations de s'exécuter en parallèle.
Contrairement à la programmation synchrone, où les tâches s'exécutent de manière séquentielle et peuvent bloquer le fil d'exécution, les méthodes asynchrones vous permettent de gérer plusieurs tâches simultanément, telles que les processus d'arrière-plan ou le traitement des entrées utilisateur, sans bloquer le fil d'exécution de l'interface utilisateur. Dans cet article, nous allons explorer comment async et await fonctionnent ensemble, couvrant des concepts tels que les méthodes async void, la gestion des erreurs, les commutations de contexte et les contextes de synchronisation. Vous apprendrez à gérer efficacement plusieurs opérations asynchrones et à gérer les exceptions, en garantissant une exécution fluide entre le thread d'appel, le thread de l'interface utilisateur et l'achèvement de la tâche. Cette approche est particulièrement utile pour les scénarios impliquant des systèmes de fichiers, des requêtes réseau ou des requêtes concurrentes où la réactivité est essentielle.
Tim présente la programmation asynchrone en expliquant la différence entre les opérations synchrones et asynchrones. Dans la programmation synchrone, les tâches sont exécutées de manière séquentielle, ce qui entraîne des retards si une tâche prend beaucoup de temps. La programmation asynchrone permet d'exécuter des tâches en parallèle ou en arrière-plan, ce qui améliore les performances et la réactivité.
Tim souligne deux avantages principaux de la programmation asynchrone :
Amélioration de la réactivité de l'interface utilisateur : en exécutant des tâches de manière asynchrone, l'interface utilisateur reste réactive même lors de l'exécution d'opérations de longue durée.
Exécution parallèle : des tâches indépendantes peuvent être exécutées en parallèle, ce qui réduit le temps total nécessaire à leur réalisation.
Tim met en place une application de démonstration Windows Presentation Foundation (WPF) pour démontrer la différence entre les opérations synchrones et asynchrones. L'application comporte deux boutons : l'un pour exécuter des tâches de manière synchrone et l'autre pour les exécuter de manière asynchrone.

L'application comprend également un panneau de résultats pour afficher les résultats.
Tim explique le code qui sous-tend l'opération synchrone. Un Stopwatch est utilisé pour mesurer le temps d'exécution de la tâche.
private void ExecuteSync_Click(object sender, RoutedEventArgs e)
{
Stopwatch stopwatch = Stopwatch.StartNew();
List<string> websites = GetWebsiteList();
foreach (var website in websites)
{
string result = DownloadWebsite(website);
ReportWebsiteInfo(website, result);
}
stopwatch.Stop();
ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}
private List<string> GetWebsiteList()
{
return new List<string>
{
"https://www.yahoo.com",
"https://www.google.com",
"https://www.microsoft.com",
"https://www.cnn.com",
"https://www.codeproject.com",
"https://www.stackoverflow.com"
};
}
private string DownloadWebsite(string websiteURL)
{
WebClient client = new WebClient();
return client.DownloadString(websiteURL);
}
private void ReportWebsiteInfo(string website, string data)
{
ResultsWindow.Text += $"{website}: {data.Length} characters{Environment.NewLine}";
}Private Sub ExecuteSync_Click(sender As Object, e As RoutedEventArgs)
Dim stopwatch As Stopwatch = Stopwatch.StartNew()
Dim websites As List(Of String) = GetWebsiteList()
For Each website In websites
Dim result As String = DownloadWebsite(website)
ReportWebsiteInfo(website, result)
Next
stopwatch.Stop()
ResultsWindow.Text &= $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}"
End Sub
Private Function GetWebsiteList() As List(Of String)
Return New List(Of String) From {
"https://www.yahoo.com",
"https://www.google.com",
"https://www.microsoft.com",
"https://www.cnn.com",
"https://www.codeproject.com",
"https://www.stackoverflow.com"
}
End Function
Private Function DownloadWebsite(websiteURL As String) As String
Dim client As New WebClient()
Return client.DownloadString(websiteURL)
End Function
Private Sub ReportWebsiteInfo(website As String, data As String)
ResultsWindow.Text &= $"{website}: {data.Length} characters{Environment.NewLine}"
End SubCe code effectue les étapes suivantes :
Tim exécute l'application pour démontrer le fonctionnement synchrone. Il note que l'interface utilisateur ne répond plus pendant le téléchargement des sites web et que les résultats s'affichent tous en même temps une fois les téléchargements terminés.

Pour une démonstration pratique du formulaire qui ne bouge pas, regardez la vidéo à 9:20 pour une meilleure compréhension.
Tim s'attaque au premier problème en convertissant la méthode synchrone en méthode asynchrone. Cela implique l'utilisation des mots-clés async et await. Voici une explication étape par étape du processus :
Copie d'une méthode synchrone existante :
private async Task RunDownloadAsync()
{
// Same code as RunDownloadSync, but will be modified for async
}
Modifier l'appel au téléchargement pour une exécution asynchrone :
Tim enveloppe l'appel de téléchargement dans un Task.Run pour l'exécuter de manière asynchrone.
private async Task<WebsiteDataModel> DownloadWebsiteAsync(string websiteURL)
{
return await Task.Run(() => DownloadWebsite(websiteURL));
}
await garantit que la méthode attend que la tâche asynchrone soit terminée avant de continuer.La signature de la méthode est mise à jour pour inclure le mot-clé async et retourne une tâche.
private async Task RunDownloadAsync()
{
List<string> websites = GetWebsiteList();
foreach (var website in websites)
{
var result = await DownloadWebsiteAsync(website);
ReportWebsiteInfo(website, result);
}
}
Gérer correctement l'événement :
private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
{
Stopwatch stopwatch = Stopwatch.StartNew();
await RunDownloadAsync();
stopwatch.Stop();
ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}
Tim montre qu'en utilisant le mot-clé await, l'interface utilisateur reste réactive. Cela permet aux utilisateurs d'interagir avec la fenêtre pendant que la tâche asynchrone s'exécute.
// UI remains responsive
private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
{
Stopwatch stopwatch = Stopwatch.StartNew();
await RunDownloadAsync();
stopwatch.Stop();
ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}' UI remains responsive
Private Async Sub ExecuteAsync_Click(sender As Object, e As RoutedEventArgs)
Dim stopwatch As Stopwatch = Stopwatch.StartNew()
Await RunDownloadAsync()
stopwatch.Stop()
ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}"
End SubPour s'assurer que le temps total d'exécution est correctement rapporté, Tim ajoute le mot-clé await à l'appel dans le gestionnaire d'événements de clic de bouton.
// Correctly waits for the asynchronous task to complete
private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
{
Stopwatch stopwatch = Stopwatch.StartNew();
await RunDownloadAsync();
stopwatch.Stop();
ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}' Correctly waits for the asynchronous task to complete
Private Async Sub ExecuteAsync_Click(sender As Object, e As RoutedEventArgs)
Dim stopwatch As Stopwatch = Stopwatch.StartNew()
Await RunDownloadAsync()
stopwatch.Stop()
ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}"
End SubEn attendant que la méthode asynchrone se termine, le temps d'exécution est mesuré avec précision et les résultats sont affichés au fur et à mesure qu'ils sont récupérés.
Tim s'attaque aux limites de l'attente séquentielle de chaque tâche en utilisant l'exécution parallèle. Voici comment il modifie le code pour y parvenir :
Copier la méthode asynchrone existante :
private async Task RunDownloadParallelAsync()
{
// Parallel execution logic will be added here
}
Créer une liste de tâches :
List<Task<WebsiteDataModel>> tasks = new List<Task<WebsiteDataModel>>();Dim tasks As New List(Of Task(Of WebsiteDataModel))()Initialiser toutes les tâches sans attendre :
foreach (var website in websites)
{
tasks.Add(DownloadWebsiteAsync(website));
}
Attendre que toutes les tâches soient terminées :
La méthode Task.WhenAll est utilisée pour attendre la fin de toutes les tâches. Cette méthode renvoie un tableau de résultats une fois que toutes les tâches sont terminées.
WebsiteDataModel[] results = await Task.WhenAll(tasks);Dim results As WebsiteDataModel() = Await Task.WhenAll(tasks)Traiter les résultats :
foreach (var result in results)
{
ReportWebsiteInfo(result);
}
Voici le code complet de la méthode d'exécution parallèle :
private async Task RunDownloadParallelAsync()
{
List<string> websites = GetWebsiteList();
List<Task<WebsiteDataModel>> tasks = new List<Task<WebsiteDataModel>>();
foreach (var website in websites)
{
tasks.Add(DownloadWebsiteAsync(website));
}
WebsiteDataModel[] results = await Task.WhenAll(tasks);
foreach (var result in results)
{
ReportWebsiteInfo(result);
}
}Private Async Function RunDownloadParallelAsync() As Task
Dim websites As List(Of String) = GetWebsiteList()
Dim tasks As New List(Of Task(Of WebsiteDataModel))()
For Each website As String In websites
tasks.Add(DownloadWebsiteAsync(website))
Next
Dim results As WebsiteDataModel() = Await Task.WhenAll(tasks)
For Each result As WebsiteDataModel In results
ReportWebsiteInfo(result)
Next
End FunctionTim met à jour le gestionnaire d'événement du clic sur le bouton pour appeler la nouvelle méthode d'exécution parallèle.
private async void ExecuteAsync_Click(object sender, RoutedEventArgs e)
{
Stopwatch stopwatch = Stopwatch.StartNew();
await RunDownloadParallelAsync();
stopwatch.Stop();
ResultsWindow.Text += $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}";
}Private Async Sub ExecuteAsync_Click(sender As Object, e As RoutedEventArgs)
Dim stopwatch As Stopwatch = Stopwatch.StartNew()
Await RunDownloadParallelAsync()
stopwatch.Stop()
ResultsWindow.Text &= $"Total execution time: {stopwatch.ElapsedMilliseconds} ms{Environment.NewLine}"
End SubEn attendant RunDownloadParallelAsync, le temps total d'exécution est mesuré et rapporté avec précision.
Tim démontre l'amélioration des performances en exécutant l'application en parallèle. Les résultats montrent une réduction significative du temps d'exécution total par rapport à l'exécution séquentielle.
// Parallel execution
async Task RunDownloadParallelAsync();' Parallel execution
Async Function RunDownloadParallelAsync() As Task
End FunctionL'augmentation de la vitesse est évidente lorsque les sites web sont téléchargés simultanément, ce qui réduit le temps d'attente total à la durée du téléchargement individuel le plus lent.
Task.Run() vs appel de méthode asyncTim explique le concept d'utilisation de Task.Run() pour enrober une méthode synchrone et la rendre asynchrone lorsque vous ne pouvez pas modifier la méthode originale. Cependant, il montre également l'approche préférée qui consiste à modifier la méthode elle-même pour qu'elle soit asynchrone si vous en avez le contrôle.
Enrobage de méthode dans Task.Run() :
private async Task<WebsiteDataModel> DownloadWebsiteAsync(string websiteURL)
{
return await Task.Run(() => DownloadWebsite(websiteURL));
}
Rendre une méthode asynchrone :
Tim démontre cela en changeant DownloadWebsite en DownloadWebsiteAsync et en utilisant DownloadStringTaskAsync de WebClient.
private async Task<WebsiteDataModel> DownloadWebsiteAsync(string websiteURL)
{
WebClient client = new WebClient();
string data = await client.DownloadStringTaskAsync(websiteURL);
return new WebsiteDataModel { URL = websiteURL, Data = data };
}
Après avoir converti la méthode, le code appelant doit être ajusté pour retirer l'enrobage Task.Run() et appeler directement la méthode asynchrone.
private async Task RunDownloadParallelAsync()
{
List<string> websites = GetWebsiteList();
List<Task<WebsiteDataModel>> tasks = new List<Task<WebsiteDataModel>>();
foreach (var website in websites)
{
tasks.Add(DownloadWebsiteAsync(website));
}
WebsiteDataModel[] results = await Task.WhenAll(tasks);
foreach (var result in results)
{
ReportWebsiteInfo(result);
}
}Private Async Function RunDownloadParallelAsync() As Task
Dim websites As List(Of String) = GetWebsiteList()
Dim tasks As New List(Of Task(Of WebsiteDataModel))()
For Each website As String In websites
tasks.Add(DownloadWebsiteAsync(website))
Next
Dim results As WebsiteDataModel() = Await Task.WhenAll(tasks)
For Each result As WebsiteDataModel In results
ReportWebsiteInfo(result)
Next
End FunctionTim conclut avec plusieurs points importants à retenir pour l'utilisation d'async et d'await :
S'assurer que les méthodes retournent des tâches : Chaque fois que vous marquez une méthode comme async, elle doit retourner un Task ou Task<t> au lieu de void (sauf pour les gestionnaires d'événements).
Utiliser await pour des opérations fiables : Utilisez le mot-clé await lorsque vous avez besoin du résultat d'une opération asynchrone avant de continuer.
Enrobage de tâche pour du code non modifiable : Utilisez Task.Run() pour enrober des méthodes synchrones lorsque vous ne pouvez pas modifier la méthode originale.
Marquer correctement les méthodes async : Ajoutez toujours Async au nom de la méthode pour indiquer qu'il s'agit d'une opération asynchrone.
Exécution parallèle ou séquentielle : Décidez si les tâches peuvent être exécutées en parallèle ou si elles doivent attendre l'une après l'autre en fonction des dépendances entre les tâches.
Tim souligne que la programmation asynchrone en C# a été simplifiée avec async, await, et Task. Les complexités telles que les contextes de threading et les modèles d'appartements sont gérées en coulisses.
Le tutoriel de Tim Corey sur async et await en C# constitue une ressource inestimable pour maîtriser la programmation asynchrone. En expliquant soigneusement des concepts tels que le parallélisme des tâches, la réactivité de l'interface utilisateur et l'importance d'utiliser async et await dans le bon contexte, Tim fournit aux développeurs les outils nécessaires pour créer des applications plus rapides et plus réactives. Sa présentation détaillée montre comment gérer efficacement les tâches de longue durée sans bloquer le thread principal, ainsi que les stratégies de gestion des opérations asynchrones et de l'exécution parallèle.
Pour une compréhension plus approfondie et des exemples pratiques supplémentaires, je recommande vivement de regarder la vidéo de Tim Corey. Sa vision des méthodes asynchrones void, de la gestion des erreurs et des contextes de synchronisation vous permettra d'améliorer votre capacité à mettre en œuvre ces concepts dans vos projets.
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!
Join our newsletter, you’ll get exclusive access on article updates. We value your privacy