Travailler avec les files d'attente de tâches en C# : pour débutants
\n\nDans le développement moderne, il est souvent nécessaire de traiter de nombreuses tâches sans bloquer le thread principal de l'application. Imaginez un serveur web qui doit répondre simultanément à des centaines d'utilisateurs, ou un service en arrière-plan traitant le téléchargement de fichiers. Dans de telles situations, la file d'attente de tâches (task queue) vient à la rescousse — l'une des structures de données et des modèles de programmation fondamentaux.
\n\nDans cet article, nous allons analyser, à l'aide d'exemples pratiques, comment fonctionnent les files d'attente de tâches en C# (.NET), en commençant par les classes de base et en terminant par des solutions thread-safe pour les applications multithread.
\n\nQu'est-ce qu'une file d'attente de tâches et pourquoi en a-t-on besoin ?
\n\nLa file d'attente (Queue) est une structure de données fonctionnant selon le principe FIFO (First In, First Out) : le premier élément ajouté sera traité en premier. Dans le contexte des tâches, cela signifie que nous pouvons placer une tâche dans la file d'attente et la traiter plus tard, lorsque les ressources seront libérées.
\n\nLes principaux scénarios d'utilisation des files d'attente de tâches :
\n- \n
- Traitement en arrière-plan (envoi d'emails, génération de rapports) \n
- Équilibrage de charge (répartition des tâches entre les threads de travail) \n
- Mise en mémoire tampon des requêtes (lorsque le système ne peut pas traiter toutes les requêtes instantanément) \n
- Journalisation asynchrone (écriture de logs sans ralentir l'application principale) \n
La classe de base Queue<T> en C#
\n\nDans .NET, il existe une classe intégrée Queue<T> de l'espace de noms System.Collections.Generic. Regardons un exemple très simple :
using System;\nusing System.Collections.Generic;\n\npublic class SimpleQueueExample\n{\n public static void Main()\n {\n // Créer une file d'attente de chaînes\n Queue<string> taskQueue = new Queue<string>();\n\n // Ajouter des tâches\n taskQueue.Enqueue("Envoyer un email au client");\n taskQueue.Enqueue("Générer un rapport");\n taskQueue.Enqueue("Mettre à jour le cache");\n\n Console.WriteLine($"Nombre de tâches dans la file d'attente : {taskQueue.Count}");\n\n // Traiter les tâches dans l'ordre\n while (taskQueue.Count > 0)\n {\n string task = taskQueue.Dequeue();\n Console.WriteLine($"Traitement : {task}");\n }\n\n Console.WriteLine($"La file d'attente est vide : {taskQueue.Count == 0}");\n }\n}\n\nLes principales méthodes de Queue<T> :
- \n
Enqueue(T item)— ajoute un élément à la fin de la file d'attente \n Dequeue()— extrait et supprime l'élément du début de la file d'attente \n Peek()— retourne le premier élément sans le supprimer \n Count— nombre d'éléments dans la file d'attente \n
Important : Queue<T> n'est pas thread-safe. Si plusieurs threads lisent et écrivent simultanément dans la file d'attente, des erreurs se produiront. Pour les scénarios multithread, utilisez ConcurrentQueue<T>.
File d'attente thread-safe : ConcurrentQueue<T>
\n\nDans les applications réelles, les files d'attente de tâches sont presque toujours utilisées dans un contexte multithread. Pour cela, .NET propose ConcurrentQueue<T> de l'espace de noms System.Collections.Concurrent.
using System;\nusing System.Collections.Concurrent;\nusing System.Threading.Tasks;\n\npublic class ConcurrentQueueExample\n{\n public static void Main()\n {\n ConcurrentQueue<string> taskQueue = new ConcurrentQueue<string>();\n\n // Tâche 1 : ajouter des éléments (Producer)\n Task producer = Task.Run(() =>\n {\n for (int i = 1; i <= 10; i++)\n {\n taskQueue.Enqueue($"Tâche #{i}");\n Console.WriteLine($"Tâche #{i} ajoutée");\n