Thread vs ThreadPool

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

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

  • Réutiliser les threads déjà créés au lieu d’en créer de nouveaux (un processus coûteux)
  • Limiter le taux de création de threads quand il y a une rafale de requêtes pour de nouveaux éléments de travail (je crois que c’est uniquement dans .NET 3.5)

    • Si vous mettez en queue 100 tâches de pool de threads, elles utiliseront uniquement autant de threads que ceux déjà créés pour traiter ces requêtes (par exemple 10). Le pool de threads effectuera des contrôles fréquents (je crois toutes les 500 ms dans 3.5 SP1) et s’il y a des tâches en queue, cela créera un nouveau thread. Si vos tâches sont rapides, le nombre de nouveaux threads sera petit et la réutilisation des 10 threads pour les tâches courtes sera plus rapide que la création de 100 threads en amont.

    • Si votre charge de travail contient systématiquement un grand nombre de demandes de pool de threads, le pool de threads se règle sur votre charge de travail en créant plus de threads dans le pool par le processus ci-dessus, afin de traiter un plus grand nombre de threads.

    • vérifier ici pour plus d’informations détaillées 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êtent à la fin du thread principal. Les threads créés manuellement sont au premier plan par défaut (ils 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.

Le threadpool géré par .NET: –

  • Taille elle-même en fonction de la charge de travail actuelle et du matériel disponible
  • Contient des threads de travail et des threads de port d’achèvement (qui sont spécifiquement utilisés pour traiter les IO)
  • Est optimisé pour un grand nombre d’opérations à durée de vie 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 caractéristique la plus importante d’un threadpool est la queue de travail. Autrement dit, une fois que votre machine est suffisamment occupée, le pool de threads mettra en queue 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 immédiatement combien de threads peuvent être créés (par exemple, ils sont créés en réponse aux entrées-sorties 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 durera longtemps, rien ne vous aidera dans la plate-forme, mais vous pourrez peut-être trouver d’autres implémentations de threadpool adaptées.

aussi

new Thread().Start()

Spawns Le 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.

J’ai été curieux de l’utilisation relative des ressources pour ces ordinateurs et j’ai lancé un benchmark sur mon ordinateur portable Intel i5 dual-core 2012 utilisant la version .net 4.0 sur Windows 8. Thread Pools a démarré en moyenne à 0.035ms où les threads prenaient en moyenne 5.06 Mme. En d’autres termes, le filetage dans la piscine a commencé environ 300 fois plus vite pour un grand nombre de fils de courte durée. Au moins dans la plage testée (100-2000), le temps total par thread semblait assez constant.

C’est le code qui a été évalué:

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

entrer la description de l'image ici

Vérifiez ici pour un thread précédent:

Quand ne devrais-je pas utiliser ThreadPool dans .Net?

Résumé est que Threadpool est bon si vous avez besoin de générer de nombreux threads à court terme, tandis que l’utilisation de Threads vous donne un peu plus de contrôle.

Le stockage local des threads n’est pas une bonne idée avec les pools de threads. Il donne aux threads une “identité”; tous les threads ne sont plus égaux. Désormais, 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 créer de surcharge.

Si vous avez besoin de beaucoup de threads, vous souhaiterez probablement utiliser un ThreadPool. Ils réutilisent les threads pour vous éviter la création de threads.

Si vous avez juste besoin d’un thread pour faire quelque chose, Thread est probablement plus facile.

Le principal besoin des threads de theadpool est de gérer de petites tâches de courte durée qui doivent se terminer presque instantanément. Les gestionnaires d’interruption de matériel s’exécutent souvent dans un contexte d’emstackment qui ne conviendrait pas pour du code autre que le kernel, mais un gestionnaire d’interruption matériel 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 sujet dans le but de faire fonctionner une telle chose serait une énorme perte de temps. Avoir quelques threads pré-créés pouvant être envoyés pour exécuter des rappels d’achèvement d’E / S ou d’autres choses similaires est beaucoup plus efficace.

Un aspect clé de ces threads est que si les méthodes d’achèvement des E / S se terminent toujours de manière essentiellement instantanée et ne bloquent jamais, et que le nombre de threads exécutant de telles méthodes est au moins égal au nombre de processeurs, pourrait s’exécuter avant que l’une des méthodes mentionnées ci-dessus se termine si l’un des autres blocs de méthodes ou son temps d’exécution dépasse une tranche de temps de threading normale; aucun de ces éléments ne devrait arriver 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 environ 100 ms au début de l’exécution, la méthode doit être exécutée par d’autres moyens que le pool de threads principal. Si l’on a beaucoup de tâches à effectuer qui consumnt beaucoup de CPU mais ne bloquent pas, il peut être utile de les répartir en utilisant un pool de threads d’application (un par cœur de processeur) distinct du pool de threads “principal”. plus de threads que de cœurs seront contre-productifs lors de l’exécution de tâches non bloquantes nécessitant une utilisation intensive du processeur. Si, toutefois, une méthode prend une seconde ou plus pour s’exécuter, et passe le plus clair de son temps bloqué, la méthode devrait probablement être exécutée dans un thread dédié, et ne devrait presque pas être exécutée dans un thread main-threadpool. Si une opération de longue durée doit être déclenchée par quelque chose comme un rappel d’E / S, il convient de lancer un thread pour l’opération longue avant le rappel et de le faire attendre sur un moniteur dont le rappel est impulsé, sinon faire en sorte que le rappel lance un nouveau thread pour effectuer l’opération pendant que le rappel se termine, renvoyant effectivement son propre thread au pool de threads.

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 à chaque thread extrait du pool et les annuler lorsqu’elles sont renvoyées une identité).

Exemple de contrainte: je n’ai que 10 connexions de firebase database, donc je n’autoriserais que 10 threads de travail pour accéder à la firebase database.

Cela ne signifie pas que vous ne devriez pas créer vos propres threads, mais il existe des conditions dans lesquelles il est judicieux d’utiliser un pool.

Utiliser un pool est une bonne idée si vous ne savez pas ou ne pouvez pas contrôler le nombre de threads créés.

Il suffit d’avoir un problème avec un formulaire utilisant un thread pour mettre à jour un champ d’une firebase database sur un événement à 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 firebase database (trop de connexion 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 de ne pas utiliser l’access), mais le regroupement est un bon début.