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
Die asynchrone Programmierung kann mit ihrer komplexen Terminologie abschreckend wirken, aber sie bietet erhebliche Vorteile, indem sie Anwendungen schneller und reaktionsschneller macht. Das Video von Tim Corey zum Thema "C# Async / Await - Machen Sie Ihre Anwendung reaktionsschneller mit asynchroner Programmierung" bietet eine praktische Anleitung zur effektiven Nutzung dieser Funktionen.
In diesem Artikel verwenden wir das ausführliche Video von Tim Corey, um diese Konzepte aufzuschlüsseln und die praktischen Anwendungen von async und await anhand klarer Beispiele zu demonstrieren. Wir werden verschiedene Szenarien abdecken, von asynchronen Ereignishandlern bis hin zum Umgang mit mehreren Aufgaben, Synchronisationskontexten, Fehlerbehandlung und den üblichen Fallstricken wie der Verwendung von asynchronen ungültigen Methoden. Am Ende dieses Artikels werden Sie ein solides Verständnis der asynchronen Programmierung haben und wissen, wie Sie diese in Ihren eigenen C#-Anwendungen implementieren können.
Asynchrone Programmierung in C# ist für die Verbesserung der Anwendungsleistung unerlässlich, insbesondere bei der Arbeit mit E/A- oder CPU-gebundenen Operationen. Die async- und await-Schlüsselwörter ermöglichen es Entwicklern, asynchronen Code zu schreiben, der langlaufende Aufgaben ausführen kann, ohne den Haupt-Thread zu blockieren. Indem Sie eine Methode mit dem Schlüsselwort async kennzeichnen, signalisieren Sie, dass die Methode eine asynchrone Operation ausführt, die eine Task oder Task<t> zurückgibt. Das await-Schlüsselwort wird innerhalb einer asynchronen Methode verwendet, um die Ausführung zu unterbrechen, bis die abgewartete Aufgabe abgeschlossen ist, sodass andere Operationen gleichzeitig ausgeführt werden können.
Im Gegensatz zur synchronen Programmierung, bei der Aufgaben sequentiell ausgeführt werden und den aufrufenden Thread blockieren können, ermöglichen asynchrone Methoden die gleichzeitige Bearbeitung mehrerer Aufgaben, z. B. Hintergrundprozesse oder die Verarbeitung von Benutzereingaben, ohne dass der UI-Thread eingefroren wird. In diesem Artikel werden wir erkunden, wie async und await zusammenarbeiten und Konzepte wie async void-Methoden, Fehlerbehandlung, Kontextwechsel und Synchronisationskontexte abdecken. Sie lernen, wie Sie mehrere asynchrone Operationen effizient verwalten und Ausnahmen behandeln, um eine reibungslose Ausführung über den aufrufenden Thread, den UI-Thread und den Abschluss der Aufgabe sicherzustellen. Dieser Ansatz ist besonders nützlich für Szenarien mit Dateisystemen, Netzwerkanfragen oder gleichzeitigen Anfragen, bei denen es auf Reaktionsfähigkeit ankommt.
Tim führt in die asynchrone Programmierung ein, indem er den Unterschied zwischen synchronen und asynchronen Operationen erklärt. Bei der synchronen Programmierung werden Aufgaben sequentiell ausgeführt, was zu Verzögerungen führt, wenn eine Aufgabe lange dauert. Bei der asynchronen Programmierung können Aufgaben parallel oder im Hintergrund ausgeführt werden, was die Leistung und Reaktionsfähigkeit verbessert.
Tim hebt zwei Hauptvorteile der asynchronen Programmierung hervor:
Verbesserte Reaktionsfähigkeit der Benutzeroberfläche: Durch die asynchrone Ausführung von Aufgaben bleibt die Benutzeroberfläche auch bei langwierigen Vorgängen reaktionsfähig.
Parallele Ausführung: Unabhängige Aufgaben können parallel ausgeführt werden, wodurch sich die Gesamtzeit, die für ihre Ausführung benötigt wird, verringert.
Tim richtet eine Windows Presentation Foundation (WPF)-Demoanwendung ein, um den Unterschied zwischen synchronen und asynchronen Operationen zu demonstrieren. Die Anwendung verfügt über zwei Schaltflächen: eine für die synchrone Ausführung von Aufgaben und eine weitere für die asynchrone Ausführung von Aufgaben.
##Demo-Anwendung##
Die Anwendung enthält auch einen Ergebnisbereich, in dem die Ausgabe angezeigt wird.
Tim erklärt den Code hinter der synchronen Operation. Ein Stopwatch wird verwendet, um die Ausführungszeit der Aufgabe zu messen.
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 SubDieser Code führt die folgenden Schritte aus:
Tim führt die Anwendung aus, um den synchronen Betrieb zu demonstrieren. Er stellt fest, dass die Benutzeroberfläche nicht mehr reagiert, während die Websites heruntergeladen werden, und dass die Ergebnisse auf einmal angezeigt werden, nachdem die Downloads abgeschlossen sind.
##Synchroner Vorgang##
Für eine praktische Demonstration des Formulars, das sich nicht bewegt, sehen Sie sich das Video zum besseren Verständnis bei 9:20 an.
Tim geht das erste Problem an, indem er die synchrone Methode in eine asynchrone Methode umwandelt. Dies beinhaltet die Verwendung der async- und await-Schlüsselwörter. Hier ist eine schrittweise Erklärung des Prozesses:
Kopieren einer vorhandenen synchronen Methode:
private async Task RunDownloadAsync()
{
// Same code as RunDownloadSync, but will be modified for async
}
Download-Aufruf für asynchrone Ausführung modifizieren:
Task.Run ein, um ihn asynchron auszuführen.private async Task<WebsiteDataModel> DownloadWebsiteAsync(string websiteURL)
{
return await Task.Run(() => DownloadWebsite(websiteURL));
}
await-Schlüsselwort stellt sicher, dass die Methode wartet, bis die asynchrone Aufgabe abgeschlossen ist, bevor sie fortfährt.Sicherstellen, dass die Methode asynchron ist:
async-Schlüsselwort einzuschließen, und es wird eine Task zurückgegeben.private async Task RunDownloadAsync()
{
List<string> websites = GetWebsiteList();
foreach (var website in websites)
{
var result = await DownloadWebsiteAsync(website);
ReportWebsiteInfo(website, result);
}
}
Richtig mit dem Ereignis umgehen:
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 zeigt, dass durch die Verwendung des await-Schlüsselworts die Benutzeroberfläche reaktionsfähig bleibt. Dies ermöglicht es den Benutzern, mit dem Fenster zu interagieren, während die asynchrone Aufgabe läuft.
// 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 SubUm sicherzustellen, dass die Gesamtausführungszeit korrekt gemeldet wird, fügt Tim das await-Schlüsselwort zum Aufruf im Button-Klick-Ereignishandler hinzu.
// 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 SubDurch das Warten auf den Abschluss der asynchronen Methode wird die Ausführungszeit genau gemessen, und die Ergebnisse werden angezeigt, sobald sie abgerufen werden.
Tim geht auf die Einschränkung ein, dass man auf die sequentielle Ausführung jeder Aufgabe warten muss, indem er die parallele Ausführung verwendet. So ändert er den Code, um dies zu erreichen:
Kopieren der vorhandenen Async-Methode:
private async Task RunDownloadParallelAsync()
{
// Parallel execution logic will be added here
}
Erstellen Sie eine Liste von Aufgaben:
List<Task<WebsiteDataModel>> tasks = new List<Task<WebsiteDataModel>>();Dim tasks As New List(Of Task(Of WebsiteDataModel))()Alle Aufgaben ohne Wartezeit einleiten:
foreach (var website in websites)
{
tasks.Add(DownloadWebsiteAsync(website));
}
Alle Aufgaben abwarten:
Task.WhenAll-Methode wird verwendet, um auf den Abschluss aller Aufgaben zu warten. Diese Methode gibt ein Array von Ergebnissen zurück, sobald alle Aufgaben abgeschlossen sind.WebsiteDataModel[] results = await Task.WhenAll(tasks);Dim results As WebsiteDataModel() = Await Task.WhenAll(tasks)Bearbeiten der Ergebnisse:
foreach (var result in results)
{
ReportWebsiteInfo(result);
}
Hier ist der vollständige Code für die parallele Ausführungsmethode:
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 aktualisiert den Ereignis-Handler für den Schaltflächenklick, um die neue parallele Ausführungsmethode aufzurufen.
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 SubDurch das Warten auf RunDownloadParallelAsync wird die Gesamtausführungszeit genau gemessen und gemeldet.
Tim demonstriert die Leistungsverbesserung, indem er die Anwendung mit paralleler Ausführung ausführt. Die Ergebnisse zeigen eine erhebliche Reduzierung der Gesamtausführungszeit im Vergleich zur sequenziellen Ausführung.
// Parallel execution
async Task RunDownloadParallelAsync();' Parallel execution
Async Function RunDownloadParallelAsync() As Task
End FunctionDer Geschwindigkeitszuwachs ist offensichtlich, da die Websites gleichzeitig heruntergeladen werden, wodurch die Gesamtwartezeit auf die Dauer des langsamsten einzelnen Downloads reduziert wird.
Task.Run() vs. Asynchroner Methodenaufruf einpackenTim erklärt das Konzept der Nutzung von Task.Run(), um eine synchrone Methode zu verpacken und sie asynchron zu machen, wenn Sie die ursprüngliche Methode nicht ändern können. Er zeigt aber auch den bevorzugten Ansatz, die Methode selbst so zu modifizieren, dass sie asynchron ist, wenn man die Kontrolle darüber hat.
Methode in Task.Run() einpacken:
private async Task<WebsiteDataModel> DownloadWebsiteAsync(string websiteURL)
{
return await Task.Run(() => DownloadWebsite(websiteURL));
}
Eine Methode asynchron machen:
Wenn Sie die Methode ändern können, ist es besser, die Methode selbst zu konvertieren, um asynchron zu sein, indem Sie eine geeignete asynchrone API verwenden.
Tim demonstriert dies, indem er DownloadWebsite in DownloadWebsiteAsync ändert und DownloadStringTaskAsync von WebClient verwendet.
private async Task<WebsiteDataModel> DownloadWebsiteAsync(string websiteURL)
{
WebClient client = new WebClient();
string data = await client.DownloadStringTaskAsync(websiteURL);
return new WebsiteDataModel { URL = websiteURL, Data = data };
}
Anpassung der Aufrufmethode:
Task.Run()-Wrapper zu entfernen und die asynchrone Methode direkt aufzurufen.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 FunctionAbschließend gibt Tim noch einige wichtige Hinweise zur Verwendung von async und await:
Sicherstellen, dass Methoden Aufgaben zurückgeben: Wann immer Sie eine Methode als async kennzeichnen, sollte sie eine Task oder Task<t> statt void zurückgeben (außer bei Ereignishandlern).
Verwenden Sie await für zuverlässige Operationen: Verwenden Sie das await-Schlüsselwort, wenn Sie das Ergebnis einer asynchronen Operation benötigen, bevor Sie fortfahren.
Task-Verpackung für nicht änderbaren Code: Verwenden Sie Task.Run(), um synchrone Methoden zu verpacken, wenn Sie die ursprüngliche Methode nicht ändern können.
Asynchrone Methoden angemessen kennzeichnen: Fügen Sie immer Async zum Methodennamen hinzu, um anzugeben, dass es sich um eine asynchrone Operation handelt.
Parallele vs. Sequentielle Ausführung: Entscheiden Sie anhand der Abhängigkeiten zwischen den Aufgaben, ob diese parallel ausgeführt werden können oder aufeinander warten sollen.
Tim betont, dass die asynchrone Programmierung in C# durch async, await und Task einfacher geworden ist. Komplexe Themen wie Threading-Kontexte und Apartment-Modelle werden im Hintergrund behandelt.
Tim Coreys Tutorial zu async und await in C# bietet eine unschätzbare Ressource für die Beherrschung der asynchronen Programmierung. Durch die sorgfältige Erläuterung von Konzepten wie Task-Parallelität, Reaktionsfähigkeit der Benutzeroberfläche und die Bedeutung der Verwendung von async und await im richtigen Kontext gibt Tim den Entwicklern die Werkzeuge an die Hand, um schnellere und reaktionsfähigere Anwendungen zu erstellen. Sein detailliertes Walkthrough zeigt, wie man effizient mit lang laufenden Aufgaben umgeht, ohne den Haupt-Thread zu blockieren, sowie Strategien zur Verwaltung asynchroner Operationen und paralleler Ausführung.
Für ein tieferes Verständnis und zusätzliche praktische Beispiele empfehle ich das Video von Tim Corey. Seine Einblicke in async void-Methoden, Fehlerbehandlung und die Verwaltung von Synchronisationskontexten werden Ihre Fähigkeit zur Implementierung dieser Konzepte in Ihren Projekten weiter verbessern.
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