CodeGym /Kurse /C# SELF /Abbrechen von asynchronen Operationen

Abbrechen von asynchronen Operationen

C# SELF
Level 42 , Lektion 4
Verfügbar

1. Einführung

Wenn du eine asynchrone (oder lang laufende) Operation startest, kann der Benutzer (oder anderer Code) plötzlich entscheiden: "Stopp! Brauche ich nicht mehr! Hör auf!". Zum Beispiel hat der Benutzer entschieden, den Download einer riesigen Datei abzubrechen, das Programmfenster geschlossen oder das Suchen in einer großen Datenbank verworfen. Ohne Unterstützung für Abbruch läuft dein Programm eventuell weiter und verbraucht Ressourcen umsonst — nicht gerade ein Zeichen von Fürsorge gegenüber Benutzer und Rechner.

Typische Abbruchszenarien:

  • Abbrechen eines Datei-Downloads oder Abbrechen des Sendens von Daten.
  • Schnelles Beenden einer aufwändigen Datenverarbeitung auf Wunsch des Benutzers.
  • Plötzliche Pause/Abbruch einer lang laufenden Aufgabe, die nicht mehr relevant ist.

Abbruch ist deine geheime Zutat für responsive, benutzerfreundliche und ressourcenschonende Anwendungen.

Wie bricht man asynchrone Operationen in .NET ab?

In .NET verwendet man für das Abbrechen lang laufender Tasks das Konzept des "Cancellation Tokens" (CancellationToken). Das ist ein spezielles Objekt, das an alle Teile einer Operation übergeben wird. Wenn jemand den Abbruch anfordert — signalisiert das Token sofort allen interessierten Teilen des Programms. Praktisch ist das wie eine rote Fahne: wer sie zuerst sieht, hört auf.

In .NET wird dieser Mechanismus durch zwei zentrale Klassen realisiert:

Wichtig: das Token alleine beendet nicht die Ausführung des Codes, es "signalisiert" nur — und deine Anwendung entscheidet dann, wann und wie sie darauf reagiert.

2. Wir erstellen ein CancellationToken und brechen eine Task ab

Schauen wir uns an, wie das in einem einfachen Beispiel funktioniert (wir erweitern unsere Lern-Console-App).

Beispiel: einfache asynchrone Operation mit Abbruch


using System;
using System.Threading;
using System.Threading.Tasks;

namespace DemoApp
{
    class Program
    {
        static async Task Main()
        {
            // Erstellen des CancellationTokenSource
            CancellationTokenSource cts = new CancellationTokenSource();

            // Starten der asynchronen Aufgabe
            Task longRunningTask = DoWorkAsync(cts.Token);

            Console.WriteLine("Drücke eine beliebige Taste, um die Operation abzubrechen...");
            Console.ReadKey();

            // Abbruch anfordern
            cts.Cancel();

            try
            {
                await longRunningTask;
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("Die Operation wurde abgebrochen!");
            }
        }

        // Asynchrone Methode, die Abbruch unterstützt
        static async Task DoWorkAsync(CancellationToken cancellationToken)
        {
            for (int i = 0; i < 10; i++)
            {
                // Auf Abbruchsignal prüfen
                cancellationToken.ThrowIfCancellationRequested();

                Console.WriteLine($"Ausführen von Schritt {i + 1}/10...");
                await Task.Delay(1000); // 1 Sekunde Verzögerung
            }

            Console.WriteLine("Operation erfolgreich abgeschlossen!");
        }
    }
}

Wie das funktioniert

- Wir erstellen einen CancellationTokenSource (cts), von dem wir das Token bekommen (cts.Token).
- Wir übergeben dieses Token an unsere asynchrone Operation.
- Innerhalb von DoWorkAsync() prüfen wir regelmäßig das Token auf Abbruch mit ThrowIfCancellationRequested(). Wenn der Benutzer den Abbruch anfordert — wirft die Methode eine OperationCanceledException und die Task wird beendet.
- In Main() warten wir auf Tastendruck und rufen cts.Cancel() auf, um das "Stopp"-Signal zu senden.

Wenn du cancellationToken.IsCancellationRequested nicht prüfst oder ThrowIfCancellationRequested() nicht aufrufst, läuft deine Task weiter wie zuvor — das Token ist nur ein informativer Flag.

3. CancellationToken: wie es aufgebaut ist? Und ein bisschen Magie

Ein CancellationToken ist ein Objekt, das einfach zwischen Methoden und Tasks weitergereicht werden kann. Das gibt viel Flexibilität:

  • Dasselbe Token kann in mehreren asynchronen und synchronen Operationen verwendet werden.
  • Man kann eine "Gruppen"-Abbruchsteuerung organisieren, wenn mehrere Operationen das Token aus derselben CancellationTokenSource verwenden.
  • Das CancellationToken ist unaufdringlich: selbst wenn du es ignorierst, läuft der Code weiter wie zuvor.

Abbruch steuern: wo und wie das Token prüfen?

Du solltest an den Stellen prüfen, wo es logisch Sinn macht: in Schleifen, bei jedem Schritt langer Verarbeitung, beim Wechsel von Etappen usw.


// An beliebiger Prüfungsstelle
if (cancellationToken.IsCancellationRequested)
{
    Console.WriteLine("Operation abgebrochen! Beende...");
    return;
}

// Oder so (kurz und mit Ausnahme)
cancellationToken.ThrowIfCancellationRequested();

Meistens verwendet man ThrowIfCancellationRequested() — das wirft eine spezielle Ausnahme, die vom aufrufenden Code gefangen werden kann.

4. Asynchrone Methoden der Standardbibliothek

Viele .NET-Klassen und -Methoden (insbesondere asynchrone) unterstützen CancellationToken direkt "out of the box". Diese solltest du nutzen, um Operationen korrekt zu stoppen.

Hier ein Beispiel fürs asynchrone Lesen aus einer Datei:


using System.IO;
using System.Threading;
using System.Threading.Tasks;

class FileDemo
{
    public static async Task ReadFileWithCancelAsync(string filePath, CancellationToken cancellationToken)
    {
        using FileStream stream = File.OpenRead(filePath);
        byte[] buffer = new byte[4096];

        int bytesRead;
        while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0)
        {
            // Daten verarbeiten...
            // Wenn das CancellationToken angefordert wurde, wirft ReadAsync selbst OperationCanceledException
        }
    }
}

Mehr zu FileStream.ReadAsync und CancellationToken findest du in der offiziellen Dokumentation.

5. Nützliche Feinheiten

Timeout ist auch ein Abbruch!

Du kannst Operationen automatisch nach einer bestimmten Zeit abbrechen. Dafür kannst du das CancellationToken "programmieren":


// CancellationTokenSource mit Timeout erstellen (z.B. 5 Sekunden)
CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));

Nach 5 Sekunden wird das Token automatisch "gesetzt" und alle Operationen mit diesem Token stoppen beim nächsten Check. Sehr praktisch, wenn du nicht ewig warten willst.

Was passiert beim Abbruch?

Wenn du Cancel() auf dem TokenSource aufrufst, erfahren alle Methoden, die dieses Token nutzen und seinen Zustand prüfen, von der Änderung. Wenn dein Code das Token aber nicht prüft — passiert kein Abbruch.

Ein typischer Fehler: vergessen, das Token an alle asynchronen/langen Aufrufe weiterzureichen. Dann wird ein Teil der Operation abgebrochen, ein anderer Teil läuft weiter, als wäre nichts passiert.

Visualisierung: wie der Abbruch abläuft

sequenceDiagram
    participant Main as Hauptthread
    participant CTS as CancellationTokenSource
    participant Task as Asynchrone Aufgabe

    Main->>CTS: erstellt CTS, bekommt Token
    Main->>Task: übergibt Token an die asynchrone Aufgabe
    Note over Task: Aufgabe prüft periodisch das Token
    Main->>CTS: ruft Cancel() auf
    CTS-->>Task: Token bekommt Status "abgebrochen"
    Task-->>Main: wirft OperationCanceledException
    Main->>Main: fängt die Ausnahme und beendet die Arbeit

Wo wird Abbruch angewendet?

  • Asynchrone Downloads und Serveranfragen: man kann bei schlechtem Internet oder ungeduldigem Benutzer abbrechen.
  • Große Berechnungen: man kann nach Timeout oder auf Benutzerwunsch stoppen.
  • Netzwerkoperationen, Dateizugriffe, Verarbeitung großer Collections im Hintergrund.

Damit ist die Einführung in das Abbrechen asynchroner Operationen fertig — jetzt wird deine Anwendung nicht nur schnell, sondern auch rücksichtsvoll!

6. Tipps und typische Fehler

Vergiss nicht, das CancellationToken an alle Methoden und Aufrufe weiterzureichen, die cancellation unterstützen. Wenn du das irgendwo nicht machst — kann die Operation "hängen bleiben" und nicht stoppen.

Prüfe das Token regelmäßig — besonders in langen Schleifen, Dateioperationen oder bei großen Downloads. Verwende IsCancellationRequested oder ThrowIfCancellationRequested().

Versuche nicht, einen Thread oder Task von außen "gewaltsam" zu beenden: ein CancellationToken ist eine Bitte zu stoppen, kein Hammer, um einen Thread außer Kraft zu setzen.

Standardbibliotheksfunktionen wie ReadAsync, Delay, HttpClient.SendAsync und viele andere unterstützen bereits Abbruch über Token. Nutze das!

Beim Handling des Abbruchs fange gezielt OperationCanceledException — das ist die spezielle Ausnahme, die über einen korrekten Abbruch durch Anfrage informiert.

1
Umfrage/Quiz
Asynchrone Dateioperationen, Level 42, Lektion 4
Nicht verfügbar
Asynchrone Dateioperationen
Vorteile der asynchronen Arbeit mit Dateien
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION