Dans cette dernière partie, nous allons voir comment annuler une opération asynchrone et comment suivre sa progression.
Annuler une opération
Pour annuler une opération asynchrone, .NET fournit les classes CancellationToken et CancellationTokenSource. Pour annuler une méthode asynchrone, il faut lui passer un objet CancellationToken en paramètre. Un CancellationToken est créé de la manière suivante:
var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token;
Une fois notre CancellationToken créé, on le passe comme paramètre à notre méthode asynchrone. Pour annuler notre traitement, il existe plusieurs méthodes. L’une d’elle consiste à surveiller la valeur de la propriété IsCancellationRequested du token. Pour lancer l’annulation de notre exécution, il faut appeler la méthode Cancel() de notre CancellationTokenSource
static void main() { var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; Task.Factory.StartNew(() => MethodeLongue(100, cancellationToken)); Console.WriteLine("Appuyer c pour annuler la tache..."); var c = Console.ReadKey(); if (c.KeyChar == 'c') { cancellationTokenSource.Cancel(); } Console.ReadKey(); } static void MethodeLongue(int nbTasks, CancellationToken ct) { for(int i = 0; i<nbtasks; i++) { Console.WriteLine($"étape {i + 1}/{nbTasks}"); Thread.Sleep(1000); //simule une opération longue if (ct.IsCancellationRequested) { Console.WriteLine("tache annulee"); return; } } }
Une autre méthode consiste à appeler la méthode ThrowIfCancellationRequested() du token. Cet appel lèvera une exception OperationCanceledException, qu’il faudra « catcher » dans la méthode appelante.
static void Main(string[] args) { var cancellationTokenSource = new CancellationTokenSource(); var cancellationToken = cancellationTokenSource.Token; Task.Factory.StartNew(() => { try { MethodeLongue(100, cancellationToken); } catch(OperationCanceledException e) { Console.WriteLine("Opération annulée"); } }); Console.WriteLine("Appuyer c pour annuler la tache..."); var c = Console.ReadKey(); if (c.KeyChar == 'c') { cancellationTokenSource.Cancel(); } Console.ReadKey(); } static void MethodeLongue(int nbTasks, CancellationToken ct) { for (int i = 0; i < nbTasks; i++) { Console.WriteLine($"étape {i + 1}/{nbTasks}"); ct.ThrowIfCancellationRequested(); Thread.Sleep(1000); //simule une opération longue } }
Suivre la progression
Pour suivre l’avancement d’une opération asynchrone, on utilise l’interface IProgress<T>. En fournissant un objet implémentant cet interface à une méthode asynchrone, on peut suivre l’état d’avancement de cette opération. Pour obtenir un objet implémentant IProgress<T> facilement, il suffit de créer une instance de la classe Progress<T>. Voyons comment ça se passe concrètement.
var progress = new Progress<int>((value) => { Console.WriteLine($"étape {value}/{nbTotal}"); });
On utilise le type int parce que c’est ce type qui est utilisé pour suivre l’avancement de notre processus. On peut en utiliser un autre. Notre objet Progress<int> est utilisé comme paramètre dans notre méthode asynchrone.
static void MaMethodeASuivre(IProgress<int> progress, int nbTasks) { for (int i = 0; i < nbTasks; i++) { if (progress != null) { progress.Report(i); } Thread.Sleep(1000); //simule une opération longue } }
Le code utilisé dans l’expression lambda à la création de notre objet Progress<int> est appelé à chaque fois qu’on appelle la méthode Report de notre Progress<int>.
Conclusion
Cette série d’article nous a permis de voir la richesse du Framework .NET. Il nous offre de nombreuses possibilités pour lancer des processus concurrents très facilement. La liste proposée dans cet article n’est pas exhaustive. En effet il existe d’autres structures qui permettent de gérer les tâches parallèles comme les Barrier.
Laisser un commentaire