Einführung in die asynchrone Programmierung in C#
Asynchrone Programmierung ist eine fundamentale Paradigma in der modernen C# (.NET)-Entwicklung, die es ermöglicht, reaktionsfähige und leistungsstarke Anwendungen zu erstellen. Im Gegensatz zum synchronen Ansatz, bei dem die Codeausführung den aktuellen Thread bis zum Abschluss der Operation blockiert, gibt asynchroner Code den Thread frei, um andere Aufgaben auszuführen, während auf das Ergebnis einer langwierigen Operation gewartet wird (z. B. Datenbankabfrage, HTTP-Aufruf oder Dateilesen).
Mit der Einführung der Schlüsselwörter async und await in C# 5.0 ist asynchrone Programmierung nicht mehr kompliziert und für jeden Entwickler zugänglich geworden. In diesem Leitfaden werden wir alle wichtigen Konzepte behandeln: von den Grundlagen von Task und ValueTask bis zur Fehlerbehandlung und dem Abbrechen von Operationen.
Grundlagen von async/await und Task
Was sind Task und Task<TResult>
Task ist der zentrale Typ in der TPL (Task Parallel Library) und stellt eine asynchrone Operation dar. Task (ohne Rückgabewert) und Task<TResult> (mit Rückgabewert) sind die Bausteine asynchronen Codes.
// Einfache asynchrone Methode ohne Rückgabewertpublic async Task DoSomethingAsync(){ await Task.Delay(1000); Console.WriteLine("Fertig!");}
// Asynchrone Methode mit Rückgabewertpublic async Task<int> CalculateSumAsync(int a, int b){ await Task.Delay(500); // Simulation einer langwierigen Operation return a + b;}Die Schlüsselwörter async und await
Der Modifikator async teilt dem Compiler mit, dass die Methode asynchronen Code enthält. Der Operator await unterbricht die Ausführung der Methode, bis die erwartete Aufgabe abgeschlossen ist, ohne den Thread zu blockieren.
public async Task ProcessDataAsync(){ Console.WriteLine("Start der Verarbeitung..."); // Asynchrones Warten – der Thread wird nicht blockiert string result = await FetchDataFromApiAsync(); Console.WriteLine($"Ergebnis erhalten: {result}");}Regeln für die Verwendung von async/await
- Verwenden Sie nicht async void (außer bei Ereignishandlern) – dies macht die Nachverfolgung von Ausnahmen unmöglich.
- Vermeiden Sie blockierende Aufrufe (
.Result,.Wait()) – sie können zu Deadlocks führen. - Benennen Sie asynchrone Methoden zur Klarheit mit dem Suffix "Async".
Fortgeschrittene Techniken: ValueTask, CancellationToken und Parallelität
ValueTask vs Task
ValueTask ist eine Optimierung für Fälle, in denen eine asynchrone Operation häufig synchron abgeschlossen wird (z. B. zwischengespeicherte Daten). Im Gegensatz zu Task, das ein Referenztyp ist, ist ValueTask eine Struktur, was die Belastung des Garbage Collectors reduziert.
public ValueTask<int> GetCachedOrFetchAsync(int id){ if (cache.ContainsKey(id)) { // Synchroner Abschluss – ohne Speicherzuweisung return new ValueTask<int>(cache[id]); } // Asynchroner Abschluss return new ValueTask<int>(FetchFromDatabaseAsync(id));}Abbrechen von Operationen mit CancellationToken
CancellationToken ermöglicht das ordnungsgemäße Unterbrechen langer asynchroner Operationen. Übergeben Sie immer ein Abbruchtoken, wenn die Methode eines akzeptiert.
public async Task<string> DownloadFileAsync(string url, CancellationToken ct){ using var client = new HttpClient(); var response = await client.GetAsync(url, ct); // ct wird an die API übergeben return await response.Content.ReadAsStringAsync();}
// Verwendungvar cts = new CancellationTokenSource();cts.CancelAfter(TimeSpan.FromSeconds(5)); // Timeout 5 Sekunden
try{ string data = await DownloadFileAsync("https://example.com", cts.Tok