Thread vs ThreadPool

137

Quelle est la différence entre l'utilisation d'un nouveau thread et l'utilisation d'un thread du pool de threads? Quels sont les avantages en termes de performances et pourquoi devrais-je envisager d'utiliser un thread du pool plutôt que celui que j'ai créé explicitement? Je pense spécifiquement à .NET ici, mais les exemples généraux sont bien.

Mark Ingram
la source

Réponses:

110

Le pool de threads offrira des avantages pour les opérations fréquentes et relativement courtes en

  • Réutiliser des threads qui ont déjà été créés au lieu d'en créer de nouveaux (un processus coûteux)
  • Limitation du taux de création de threads lorsqu'il y a une rafale de demandes de nouveaux éléments de travail (je crois que ce n'est que dans .NET 3.5)

    • Si vous mettez en file d'attente 100 tâches de pool de threads, il n'utilisera que le nombre de threads déjà créés pour traiter ces requêtes (disons 10 par exemple). Le pool de threads effectuera des vérifications fréquentes (je crois toutes les 500 ms dans 3.5 SP1) et s'il y a des tâches en file d'attente, il créera un nouveau thread. Si vos tâches sont rapides, le nombre de nouveaux threads sera petit et la réutilisation de la dizaine de threads pour les tâches courtes sera plus rapide que de créer 100 threads à l'avance.

    • Si votre charge de travail a systématiquement un grand nombre de requêtes de pool de threads entrant, le pool de threads s'accordera à votre charge de travail en créant plus de threads dans le pool par le processus ci-dessus afin qu'il y ait un plus grand nombre de threads disponibles pour traiter les demandes.

    • Vérifiez ici pour plus d'informations sur le fonctionnement du pool de threads sous le capot

Créer un nouveau thread vous-même serait plus approprié si le travail devait être relativement long (probablement environ une seconde ou deux, mais cela dépend de la situation spécifique)

@Krzysztof - Les threads du pool de threads sont des threads d'arrière-plan qui s'arrêteront lorsque le thread principal se termine. Les threads créés manuellement sont au premier plan par défaut (continueront à s'exécuter après la fin du thread principal), mais peuvent être définis en arrière-plan avant d'appeler Start sur eux.

Karg
la source
5
La seule chose sur laquelle je m'interroge est la déclaration suivante de MSDN ( msdn.microsoft.com/en-us/library/1c9txz50.aspx ) "Un thread d'arrière-plan s'exécute uniquement lorsque le nombre de threads de premier plan en cours d'exécution est inférieur au nombre de processeurs . ". Cela signifie-t-il que lors de la division du travail entre les cœurs, les threads de premier plan ont la priorité?
cdiggins
1
➤ Vous ne pouvez pas abandonner ou interrompre un thread du pool de threads. ➤ Vous ne pouvez pas rejoindre un thread à partir du pool de threads. Pour y parvenir, vous devez utiliser d'autres mécanismes
Zinov
14

Le pool de threads géré .NET: -

  • Se taille en fonction de la charge de travail actuelle et du matériel disponible
  • Contient les threads de travail et les threads de port d'achèvement (qui sont spécifiquement utilisés pour desservir les E / S)
  • Est optimisé pour un grand nombre d'opérations de durée relativement courte

Il existe d'autres implémentations de pool de threads qui pourraient être plus appropriées pour les opérations de longue durée.

Plus précisément, utilisez un pool de threads pour empêcher votre application de créer trop de threads. La fonction la plus importante d'un pool de threads est la file d'attente de travail. Autrement dit, une fois que votre machine est suffisamment occupée, le pool de threads mettra en file d'attente les requêtes plutôt que de générer immédiatement plus de threads.

Donc, si vous créez un petit nombre limité de threads, créez-les vous-même. Si vous ne pouvez pas déterminer à l'avance le nombre de threads qui peuvent être créés (par exemple, ils sont créés en réponse aux E / S entrantes) et que leur travail sera de courte durée, utilisez le pool de threads. Si vous ne savez pas combien, mais que leur travail sera de longue durée, il n'y a rien dans la plate-forme pour vous aider - mais vous pourrez peut-être trouver d'autres implémentations de threadpool qui conviennent.

Martin
la source
Dans .NET, pouvez-vous utiliser des ports d'achèvement sans le pool de threads? J'étais sous l'hypothèse que les méthodes d'E / S asynchrones étaient le seul moyen (dans .NET) et qu'elles utilisaient le pool de threads
Karg
10

aussi

new Thread().Start()

génère un thread de premier plan qui ne mourra pas si vous fermez votre programme. Les threads ThreadPool sont des threads d'arrière-plan qui meurent lorsque vous fermez l'application.


la source
11
Vous pouvez toujours définir un fil en arrière-plan. Ils sont juste au premier plan par défaut.
Kris Erickson
3
nemo: var t = new Thread (...); t.BackgroundThread = vrai; t.Start ();
Ricardo Amores
18
Clarification concernant le terme «programme». Une application de bureau s'exécute dans un processus et possède au moins un thread de premier plan qui gère l'interface utilisateur. Ce processus continuera à s'exécuter tant qu'il aura des threads de premier plan. Lorsque vous fermez une application de bureau, le thread d'interface utilisateur de premier plan s'arrête, mais vous n'avez pas nécessairement arrêté le processus s'il a d'autres threads de premier plan.
G-Wiz
8

J'étais curieux de l'utilisation relative des ressources pour ceux-ci et j'ai exécuté un benchmark sur mon ordinateur portable Intel i5 bicœur 2012 en utilisant la version .net 4.0 construite sur Windows 8. Les pools de threads prenaient en moyenne 0,035 ms pour démarrer là où les threads prenaient en moyenne 5,06 SP. En d'autres termes, le thread dans le pool a démarré environ 300 fois plus vite pour un grand nombre de threads de courte durée. Au moins dans la plage testée (100-2000) threads, le temps total par thread semblait assez constant.

C'est le code qui a été comparé:

    for (int i = 0; i < ThreadCount; i++) {
        Task.Run(() => { });
    }

    for (int i = 0; i < ThreadCount; i++) {
        var t = new Thread(() => { });
        t.Start();
    }

entrez la description de l'image ici

PeterM
la source
5
Je pense que c'est parce que le ThreadPool réutilise les fils créés au lieu d'en créer de nouveaux (ce qui est très cher)
fabriciorissetto
1

Le stockage local de threads n'est pas une bonne idée avec les pools de threads. Cela donne aux fils une "identité"; tous les threads ne sont plus égaux. Maintenant, les pools de threads sont particulièrement utiles si vous avez juste besoin d'un tas de threads identiques, prêts à faire votre travail sans surcharge de création.

MSalters
la source
1

Si vous avez besoin de beaucoup de threads, vous souhaiterez probablement utiliser un ThreadPool. Ils réutilisent les threads, ce qui vous évite la surcharge de création de threads.

Si vous n'avez besoin que d'un thread pour faire quelque chose, Thread est probablement le plus simple.

Rob Prouse
la source
1

Le besoin principal des threads de pool est de gérer de petites tâches courtes qui devraient se terminer presque instantanément. Les gestionnaires d'interruptions matérielles s'exécutent souvent dans un contexte d'empilement qui ne conviendrait pas au code non-noyau, mais un gestionnaire d'interruptions matérielles peut découvrir qu'un rappel d'achèvement d'E / S en mode utilisateur doit être exécuté dès que possible. Créer un nouveau thread dans le but d'exécuter une telle chose serait excessif. Il est beaucoup plus efficace d'avoir quelques threads pré-créés qui peuvent être envoyés pour exécuter des rappels d'achèvement d'E / S ou d'autres choses similaires.

Un aspect clé de ces threads est que si les méthodes d'achèvement d'E / S se terminent toujours essentiellement instantanément et ne bloquent jamais, et que le nombre de ces threads qui exécutent actuellement de telles méthodes est au moins égal au nombre de processeurs, le seul moyen pour tout autre thread pourrait s'exécuter avant la fin de l'une des méthodes susmentionnées si l'une des autres méthodes se bloque ou si son temps d'exécution dépasse une tranche de temps de threading normale; aucun de ces problèmes ne devrait se produire très souvent si le pool de threads est utilisé comme prévu.

Si l'on ne peut pas s'attendre à ce qu'une méthode se termine dans les 100 ms environ après le début de l'exécution, la méthode doit être exécutée via un autre moyen que le pool de threads principal. Si l'on a beaucoup de tâches à effectuer qui sont gourmandes en CPU mais qui ne bloquent pas, il peut être utile de les répartir en utilisant un pool de threads d'application (un par cœur de CPU) qui est séparé du threadpool "principal", depuis l'utilisation plus de threads que de cœurs seront contre-productifs lors de l'exécution de tâches non bloquantes gourmandes en ressources processeur. Si, cependant, une méthode prend une seconde ou plus à s'exécuter et passe la plupart de son temps bloquée, la méthode devrait probablement être exécutée dans un thread dédié et ne devrait presque certainement pas être exécutée dans un thread du pool de threads principal. Si une opération de longue durée doit être déclenchée par quelque chose comme un rappel d'E / S,

supercat
la source
0

En général (je n'ai jamais utilisé .NET), un pool de threads serait utilisé à des fins de gestion des ressources. Il permet de configurer des contraintes dans votre logiciel. Cela peut également être fait pour des raisons de performances, car la création de nouveaux threads peut être coûteuse.

Il peut également y avoir des raisons spécifiques au système. En Java (encore une fois, je ne sais pas si cela s'applique à .NET), le gestionnaire des threads peut appliquer des variables spécifiques aux threads lorsque chaque thread est extrait du pool, et les annuler lorsqu'ils sont retournés (moyen courant de transmettre quelque chose comme une identité).

Exemple de contrainte: je n'ai que 10 connexions db, donc je n'autoriserais que 10 threads de travail pour accéder à la base de données.

Cela ne signifie pas que vous ne devez pas créer vos propres threads, mais il y a des conditions dans lesquelles il est logique d'utiliser un pool.

Robin
la source
0

L'utilisation d'un pool est une bonne idée, si vous ne savez pas ou ne pouvez pas contrôler le nombre de threads qui seront créés.

J'ai juste un problème avec un formulaire utilisant un thread pour mettre à jour un champ d'une base de données sur un événement de changement de position d'un contrôle de liste (éviter le gel). Il a fallu 5 minutes à mon utilisateur pour avoir une erreur de la base de données (trop de connexions avec Access) car il changeait trop rapidement la position de la liste ...

Je sais qu'il existe un autre moyen de résoudre le problème de base (y compris ne pas utiliser l'accès), mais la mise en commun est un bon début.

Marco Guignard
la source
0

Fil :

  1. Créer un Thread est beaucoup plus lent que d'utiliser Thread-pool.
  2. Vous pouvez modifier la priorité d'un thread.
  3. Le nombre maximum de threads dans un processus lié aux ressources.
  4. Le thread est au niveau du système d'exploitation et contrôlé par le système d'exploitation.
  5. L'utilisation de Thread est une meilleure option lorsque la tâche est relativement longue

Thread-Pool :

  1. Exécuter un thread sur un pool de threads est beaucoup plus rapide que de créer directement un thread.
  2. Vous ne pouvez pas modifier la priorité d'une exécution de thread en fonction du pool de threads.
  3. Il n'y a qu'un seul Thread-pool par processus.
  4. Le Thread-pool est géré par CLR.
  5. Le Thread-pool est utile pour un fonctionnement de courte durée.
  6. Le nombre de threads dans le pool de threads est lié à la charge de l'application.
  7. Les tâches TPL s'exécutent en fonction du pool de threads
Seyedraouf Modarresi
la source