Introduction : pourquoi utiliser des files d'attente de tâches en C# ?
Imaginez que vous développez une application qui traite les commandes dans une boutique en ligne. Les clients envoient des requêtes simultanément, et chaque requête prend du temps (par exemple, vérification du paiement ou envoi d'un email). Si vous les traitez séquentiellement, l'application ralentira et les utilisateurs attendront. La solution est d'utiliser une file d'attente de tâches.
Une file d'attente de tâches (Task Queue) est une structure de données fonctionnant selon le principe FIFO (First In, First Out — « premier arrivé, premier sorti »). En C# (.NET), les files d'attente sont implémentées en plusieurs variantes : de la simple Queue<T> à la file thread-safe ConcurrentQueue<T>. Dans cet article, nous verrons comment créer des files d'attente, ajouter et extraire des tâches, et comment les utiliser en programmation asynchrone.
Cet article est destiné aux débutants, nous commencerons donc par les bases et passerons progressivement à des exemples plus complexes.
1. Bases de l'utilisation de Queue<T> en C#
La classe Queue<T> se trouve dans l'espace de noms System.Collections.Generic. C'est une file d'attente simple qui ne prend pas en charge le multithreading — elle doit être utilisée uniquement dans des scénarios monothread.
Création d'une file d'attente et opérations de base
Créons une file d'attente pour stocker des tâches sous forme de chaînes de caractères :
using System;using System.Collections.Generic;
class Program{ static void Main() { // Création d'une file d'attente de chaînes Queue<string> taskQueue = new Queue<string>();
// Ajout de tâches (Enqueue) taskQueue.Enqueue("Envoyer un email au client"); taskQueue.Enqueue("Vérifier le statut de la commande"); taskQueue.Enqueue("Mettre à jour la base de données");
Console.WriteLine($"Nombre de tâches : {taskQueue.Count}");
// Extraction d'une tâche (Dequeue) — supprime et retourne le premier élément string firstTask = taskQueue.Dequeue(); Console.WriteLine($"Exécution : {firstTask}");
// Consultation de la tâche suivante sans suppression (Peek) string nextTask = taskQueue.Peek(); Console.WriteLine($"Suivante : {nextTask}");
Console.WriteLine($"Tâches restantes : {taskQueue.Count}"); }}Sortie du programme :
Nombre de tâches : 3Exécution : Envoyer un email au clientSuivante : Vérifier le statut de la commandeTâches restantes : 2Méthodes importantes de Queue<T>
Enqueue(item)— ajoute un élément à la fin de la file d'attente.Dequeue()— supprime et retourne le premier élément. Si la file est vide, lève une exceptionInvalidOperationException.Peek()— retourne le premier élément sans le supprimer.Clear()— vide la file d'attente.Contains(item)— vérifie si un élément est présent dans la file.
Important : Queue<T> n'est pas thread-safe. Si plusieurs threads ajoutent ou extraient des éléments simultanément, des erreurs se produiront. Pour les scénarios multithread, utilisez ConcurrentQueue<T>.
2. File d'attente thread-safe : ConcurrentQueue<T>
Dans les applications réelles, les tâches sont souvent ajoutées et traitées dans différents threads. Pour cela, .NET propose ConcurrentQueue<T> de l'espace de noms System.Collections.Concurrent.
Exemple : Producer-Consumer (Producteur-Consommateur)
Imaginez qu'un thread (Producer) génère des tâches et qu'un autre (Consumer) les exécute.
using System;using System.Collections.Concurrent;using System.Threading.Tasks;
class Program{ static void Main() { ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
// Producteur : ajoute des tâches