CodeGym /Cours /C# SELF /Annulation des opérations asynchrones

Annulation des opérations asynchrones

C# SELF
Niveau 42 , Leçon 4
Disponible

1. Introduction

Quand vous lancez une opération asynchrone (ou longue), l'utilisateur (ou un autre morceau de code) peut soudain décider : "Stop ! Plus besoin ! Arrête-toi !". Par exemple, l'utilisateur peut vouloir interrompre le téléchargement d'un fichier énorme, fermer la fenêtre du programme ou changer d'avis pour une recherche dans une grosse base de données. Sans prise en charge de l'annulation, votre programme peut continuer à tourner et consommer des ressources inutilement — pas très sympa pour l'utilisateur ni pour l'ordinateur.

Scénarios typiques d'annulation :

  • Annulation du téléchargement d'un fichier ou annulation de l'envoi de données.
  • Sortie rapide d'un traitement de données complexe à la demande de l'utilisateur.
  • Interruption/arrêt brutal d'une tâche longue qui n'est plus pertinente.

L'annulation — c'est votre ingrédient secret pour des applications réactives, conviviales et économes.

Comment annuler des opérations asynchrones en .NET ?

En .NET, on utilise la notion de "token d'annulation" (CancellationToken) pour arrêter des tâches longues. C'est un objet spécial qu'on passe à tous les composants d'une tâche. Si quelqu'un demande l'annulation — le token signale immédiatement à toutes les parties intéressées. En pratique, c'est comme un drapeau rouge : qui le voit en premier s'arrête.

En .NET, ce mécanisme est implémenté par deux classes clés :

Important : le token d'annulation lui-même n'interrompt pas l'exécution du code, il se contente de "signaler" — c'est votre application qui décide quand et comment réagir à ce signal.

2. Créons un token d'annulation et annulons une tâche

Voyons comment cela fonctionne avec un exemple simple (on va développer notre application console pédagogique).

Exemple : opération asynchrone simple avec annulation


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

namespace DemoApp
{
    class Program
    {
        static async Task Main()
        {
            // Create a cancellation token source
            CancellationTokenSource cts = new CancellationTokenSource();

            // Start an asynchronous task
            Task longRunningTask = DoWorkAsync(cts.Token);

            Console.WriteLine("Appuyez sur une touche pour annuler l'opération...");
            Console.ReadKey();

            // Request cancellation
            cts.Cancel();

            try
            {
                await longRunningTask;
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("L'opération a été annulée !");
            }
        }

        // Asynchronous method, that supports cancellation
        static async Task DoWorkAsync(CancellationToken cancellationToken)
        {
            for (int i = 0; i < 10; i++)
            {
                // Check for a cancellation signal*
                cancellationToken.ThrowIfCancellationRequested();

                Console.WriteLine($"Exécution de l'étape {i + 1}/10...");
                await Task.Delay(1000); // Delay 1 second
            }

            Console.WriteLine("L'opération s'est terminée avec succès !");
        }
    }
}

Comment ça marche ?

- Nous créons un CancellationTokenSource (cts), d'où on obtient le token (cts.Token).
- Nous passons ce token à notre opération asynchrone.
- À l'intérieur de DoWorkAsync(), on vérifie régulièrement le token avec la méthode ThrowIfCancellationRequested(). Si l'utilisateur demande l'annulation — la méthode lance une OperationCanceledException, et la tâche s'arrête.
- Dans Main(), on attend l'appui sur une touche et on appelle cts.Cancel() pour "signaler" l'arrêt de l'opération.

Si vous ne vérifiez pas cancellationToken.IsCancellationRequested ou n'appelez pas ThrowIfCancellationRequested(), votre tâche continuera à fonctionner comme si de rien n'était — le token n'est qu'un drapeau informatif.

3. CancellationToken : comment c'est fait ? Et un peu de magie

Le token d'annulation est un objet qu'on peut facilement passer entre méthodes et tâches. Ça donne beaucoup de flexibilité :

  • Le même token peut être utilisé dans plusieurs opérations asynchrones et synchrones.
  • On peut organiser une annulation "de groupe" pour toutes les tâches si plusieurs opérations utilisent le token issu d'un même CancellationTokenSource.
  • Le token est discret : même si vous l'ignorez, le code continuera de fonctionner comme avant.

Gérer l'annulation : où et comment vérifier le token ?

Vous devez vérifier si le "drapeau d'annulation" a été levé aux endroits logiques : dans les boucles, à chaque étape d'un long traitement, lors des transitions entre étapes, etc.


// At any point during the checks
if (cancellationToken.IsCancellationRequested)
{
    Console.WriteLine("Opération annulée ! On sort...");
    return;
}

// Or like this (shorter, with an exception being thrown)
cancellationToken.ThrowIfCancellationRequested();

On utilise généralement ThrowIfCancellationRequested() — il lance une exception spéciale qui peut être interceptée dans le code appelant.

4. Méthodes asynchrones de la bibliothèque standard

Beaucoup de classes et méthodes .NET (surtout asynchrones) supportent CancellationToken directement "out of the box". Il faut les utiliser pour arrêter correctement les opérations.

Voici un exemple de lecture de fichier asynchrone :


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)
        {
            // Process the data...
            // If a cancellation token was requested, ReadAsync itself will throw an OperationCanceledException
        }
    }
}

Plus d'infos sur FileStream.ReadAsync et CancellationToken dans la documentation officielle.

5. Astuces utiles

Timeout — c'est aussi une annulation !

Vous pouvez annuler automatiquement des opérations après un délai donné. Pour ça, on peut "programmer" le CancellationToken :


// Create CancellationTokenSource with timeout (for example, 5 seconds)
CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));

Au bout de 5 secondes, le token sera automatiquement "levé" et toutes les opérations l'utilisant s'arrêteront à la prochaine vérification. Très pratique si vous ne voulez pas attendre indéfiniment.

Que se passe-t-il lors d'une annulation ?

Quand vous appelez Cancel() sur le source du token, toutes les méthodes qui utilisent ce token et vérifient son état apprennent la nouvelle. Mais si votre code ne vérifie pas le token — l'annulation ne se produira pas.

Erreur typique : oublier de passer le token à toutes les opérations asynchrones et longues. Alors une partie sera annulée et une autre continuera comme si de rien n'était.

Visualisation : comment l'annulation se déroule

sequenceDiagram
    participant Main as Thread principal
    participant CTS as CancellationTokenSource
    participant Task as Tâche asynchrone

    Main->>CTS: crée CTS, obtient le token
    Main->>Task: passe le token à la tâche asynchrone
    Note over Task: La tâche vérifie périodiquement le token
    Main->>CTS: appelle Cancel()
    CTS-->>Task: le token reçoit le statut "annulé"
    Task-->>Main: lance OperationCanceledException
    Main->>Main: attrape l'exception et termine le travail

Où l'annulation est-elle utilisée ?

  • Téléchargements asynchrones et requêtes vers des serveurs : on peut annuler en cas de connexion lente ou si l'utilisateur abandonne.
  • Calculs lourds : on peut arrêter via timeout ou à la demande de l'utilisateur.
  • Opérations réseau, gestion de fichiers, traitement de grosses collections en background.

Voilà pour la présentation de l'annulation des opérations asynchrones — votre application sera désormais non seulement rapide, mais aussi attentionnée !

6. Conseils et erreurs typiques

N'oubliez pas de passer le token d'annulation à toutes les méthodes et appels qui supportent la cancellation. Si vous l'omettez quelque part — l'opération peut "se coincer" et ne pas s'arrêter.

Vérifiez régulièrement le token — surtout dans les longues boucles, traitements de fichiers ou lors de téléchargements de gros volumes. Utilisez IsCancellationRequested ou ThrowIfCancellationRequested().

Ne tentez pas de "forcer" l'arrêt d'un thread ou d'une tâche depuis l'extérieur : le token d'annulation est une demande polie d'arrêt, pas un marteau pour frapper le thread.

Les fonctions de la bibliothèque standard, comme ReadAsync, Delay, HttpClient.SendAsync et beaucoup d'autres, supportent déjà l'annulation via token. Utilisez-les !

Lors de la gestion de l'annulation, capturez spécifiquement OperationCanceledException — c'est l'exception qui indique une annulation correcte suite à une requête.

1
Étude/Quiz
Opérations asynchrones avec les fichiers, niveau 42, leçon 4
Indisponible
Opérations asynchrones avec les fichiers
Les avantages du travail asynchrone avec les fichiers
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION