Le pool de threads managés
La classe System.Threading.ThreadPool fournit à votre application un pool de threads de travail qui sont gérés par le système, ce qui vous permet de vous concentrer sur les tâches d’application plutôt que sur la gestion des threads. Si vous avez des tâches courtes qui nécessitent un traitement en arrière-plan, le pool de threads managés est un moyen simple de tirer parti de plusieurs threads. L’utilisation du pool de threads est beaucoup plus facile dans Framework 4 et ultérieur, car vous pouvez créer des objets Task et Task<TResult> qui effectuent des tâches asynchrones sur les threads de pool.
.NET utilise des threads de pool pour de nombreux scénarios, notamment les opérations de bibliothèque parallèle de tâches (TPL), l’achèvement des E/S asynchrones, les rappels de timer, les opérations d’attente inscrites, les appels de méthodes asynchrones utilisant des délégués et les connexions de sockets System.Net.
Caractéristiques du pool de threads
Les threads de pool sont des threads d’arrière-plan. Chaque thread utilise la taille de pile par défaut, s'exécute avec la priorité par défaut et se trouve dans le multithread cloisonné. Une fois qu’un thread du pool de threads a terminé sa tâche, il est retourné à une file d’attente de threads en attente. À partir de ce moment, il peut être réutilisé. Cette réutilisation permet aux applications d’éviter le coût lié à la création d’un nouveau thread pour chaque tâche.
Il n'y a qu'un seul pool de threads par processus.
Exceptions dans les threads de pool
Les exceptions non gérées dans les threads de pool entraînent la fin du processus. Il y a trois exceptions à cette règle :
- Une System.Threading.ThreadAbortException est levée dans un thread de pool, car Thread.Abort a été appelée.
- Une System.AppDomainUnloadedException est levée dans un thread de pool, car le domaine d’application est en cours de déchargement.
- Le common language runtime ou un processus hôte met fin au thread.
Pour plus d'informations, voir Exceptions dans les threads managés.
Nombre maximal de threads dans un pool
Le nombre d’opérations qui peuvent être mises en file d’attente pour le pool de threads est limité seulement par la mémoire disponible. Cependant, le pool de threads limite le nombre de threads qui peuvent être actifs simultanément dans le processus. Si tous les threads du pool sont occupés, les éléments de travail supplémentaires sont mis en file d’attente jusqu’à ce que des threads soient disponibles pour les exécuter. La taille par défaut du pool de threads d’un processus dépend de plusieurs facteurs, dont la taille de l’espace d’adressage virtuel. Un processus peut appeler la méthode ThreadPool.GetMaxThreads pour déterminer le nombre de threads.
Vous pouvez contrôler le nombre maximal de threads à l'aide des méthodes ThreadPool.GetMaxThreads et ThreadPool.SetMaxThreads.
Notes
Le code qui héberge le Common Language Runtime peut définir la taille avec la méthode ICorThreadpool::CorSetMaxThreads
.
Valeurs minimales d’un pool de threads
Le pool de threads fournit de nouveaux threads de travail ou des threads de terminaison d'E/S à la demande jusqu'à ce qu'il atteigne la valeur minimale spécifiée pour chaque catégorie. Vous pouvez utiliser la méthode ThreadPool.GetMinThreads pour obtenir ces valeurs minimales.
Notes
Quand la demande est faible, le nombre réel de threads du pool peut être inférieur aux valeurs minimales.
Quand une valeur minimale est atteinte, le pool de threads peut créer des threads supplémentaires ou attendre que certaines tâches soient terminées. Le pool de threads crée et détruit des threads de travail pour optimiser le débit, qui est défini comme le nombre de tâches exécutées par unité de temps. Un nombre trop bas de threads peut ne pas permettre une utilisation optimale des ressources disponibles, tandis qu'un nombre trop élevé de threads peut augmenter les conflits de ressources.
Attention
Vous pouvez utiliser la méthode ThreadPool.SetMinThreads pour augmenter le nombre minimal de threads inactifs. Toutefois, une augmentation non nécessaire de ces valeurs peut entraîner des problèmes de performances. Si vous démarrez trop de tâches en même temps, celles-ci seront lentes. Dans la plupart des cas, le pool de threads sera plus performant avec son propre algorithme d'allocation de threads.
Utilisation du pool de threads
Le moyen le plus simple d’utiliser le pool de threads est d’utiliser la bibliothèque parallèle de tâches (TPL). Par défaut, les types de la bibliothèque parallèle de tâches, comme Task et Task<TResult>, utilisent des threads de pool pour exécuter des tâches.
Vous pouvez également utiliser le pool de threads en appelant ThreadPool.QueueUserWorkItem depuis du code managé (ou ICorThreadpool::CorQueueUserWorkItem
depuis du code non managé) et en passant un délégué System.Threading.WaitCallback représentant la méthode qui effectue la tâche.
Une autre façon d’utiliser le pool de threads est de mettre en file d’attente des éléments de travail associés à une opération d’attente en utilisant la méthode ThreadPool.RegisterWaitForSingleObject et en passant un System.Threading.WaitHandle qui, quand il est signalé ou quand il a expiré, appelle la méthode représentée par le délégué System.Threading.WaitOrTimerCallback. Les threads de pool sont utilisés pour appeler les méthodes de rappel.
Pour obtenir des exemples, consultez les pages des API référencées.
Ignorer les vérifications de sécurité
Le pool de threads fournit également les méthodes ThreadPool.UnsafeQueueUserWorkItem et ThreadPool.UnsafeRegisterWaitForSingleObject. Ces méthodes ne doivent être utilisées que si vous êtes certain que la pile de l'appelant n'a pas fait l'objet de vérifications de sécurité effectuées pendant l'exécution de la tâche mise en file d'attente. ThreadPool.QueueUserWorkItem et ThreadPool.RegisterWaitForSingleObject capturent la pile de l'appelant, qui est fusionnée avec la pile du thread de pool quand le thread commence à exécuter une tâche. Si une vérification de sécurité est requise, la pile entière doit être vérifiée. Même si elle garantit une sécurité, cette vérification a un impact sur les performances.
Quand ne pas utiliser les threads de pool
Il existe plusieurs scénarios dans lesquels il est préférable de créer et de gérer vos propres threads au lieu d’utiliser des threads de pool :
- Si vous devez utiliser un thread de premier plan.
- Si un thread doit avoir une priorité particulière.
- Si vous avez des tâches qui entraînent le blocage du thread pendant une longue durée. Le pool de threads possède un nombre maximal de threads. Un grand nombre de threads de pool bloqués pourrait donc empêcher le démarrage des tâches.
- Vous devez placer les threads dans un thread unique cloisonné. Tous les threads ThreadPool se trouvent dans le multithread cloisonné.
- Vous avez besoin d'une identité stable associée au thread ou avez besoin de dédier un thread à une tâche.