Si vous avez beaucoup de tâches logiques qui nécessitent un traitement constant et que vous souhaitez que cela se fasse en parallèle, utilisez le pool + planificateur.
Si vous devez effectuer vos tâches liées aux E / S simultanément, telles que le téléchargement de données à partir de serveurs distants ou l'accès au disque, mais que vous devez le faire toutes les quelques minutes, créez vos propres threads et tuez-les une fois que vous avez terminé.
Edit: À propos de certaines considérations, j'utilise des pools de threads pour l'accès à la base de données, la physique / simulation, l'IA (jeux) et pour les tâches scriptées exécutées sur des machines virtuelles qui traitent de nombreuses tâches définies par l'utilisateur.
Normalement, un pool se compose de 2 threads par processeur (donc probablement 4 de nos jours), mais vous pouvez configurer la quantité de threads que vous voulez, si vous savez combien vous en avez besoin.
Edit: La raison pour laquelle vous créez vos propres threads est à cause des changements de contexte, (c'est quand les threads ont besoin d'échanger dans et hors du processus, avec leur mémoire). Avoir des changements de contexte inutiles, par exemple lorsque vous n'utilisez pas vos threads, en les laissant simplement assis comme on pourrait le dire, peut facilement réduire la moitié des performances de votre programme (disons que vous avez 3 threads en veille et 2 threads actifs). Ainsi, si ces threads de téléchargement attendent juste, ils consomment des tonnes de CPU et refroidissent le cache pour votre application réelle.
Je vous suggère d'utiliser un pool de threads en C # pour les mêmes raisons que tout autre langage.
Lorsque vous souhaitez limiter le nombre de threads en cours d'exécution ou que vous ne voulez pas la surcharge de création et de destruction, utilisez un pool de threads.
Par petites tâches, le livre que vous lisez signifie des tâches à courte durée de vie. S'il faut dix secondes pour créer un thread qui ne fonctionne que pendant une seconde, c'est un endroit où vous devriez utiliser des pools (ignorez mes chiffres réels, c'est le ratio qui compte).
Sinon, vous passez le plus clair de votre temps à créer et à détruire des threads plutôt que de simplement faire le travail qu'ils sont censés faire.
la source
Voici un joli résumé du pool de threads dans .Net: http://blogs.msdn.com/pedram/archive/2007/08/05/dedicated-thread-or-a-threadpool-thread.aspx
La publication a également quelques points sur le moment où vous ne devez pas utiliser le pool de threads et démarrer votre propre thread à la place.
la source
Je recommande vivement de lire ce livre électronique gratuit: Threading in C # par Joseph Albahari
Au moins, lisez la section «Premiers pas». Le livre électronique fournit une excellente introduction et comprend également une mine d'informations avancées sur les fils.
Savoir s'il faut utiliser ou non le pool de threads n'est qu'un début. Ensuite, vous devrez déterminer quelle méthode d'entrée dans le pool de threads correspond le mieux à vos besoins:
Cet e-book explique tout cela et vous conseille quand les utiliser ou créer votre propre fil.
la source
Le pool de threads est conçu pour réduire le changement de contexte entre vos threads. Considérez un processus qui a plusieurs composants en cours d'exécution. Chacun de ces composants peut créer des threads de travail. Plus votre processus comporte de threads, plus vous perdez de temps à changer de contexte.
Désormais, si chacun de ces composants mettait des éléments en file d'attente dans le pool de threads, vous auriez beaucoup moins de surcharge de changement de contexte.
Le pool de threads est conçu pour maximiser le travail effectué sur vos processeurs (ou cœurs de processeur). C'est pourquoi, par défaut, le pool de threads fait tourner plusieurs threads par processeur.
Il existe certaines situations dans lesquelles vous ne souhaitez pas utiliser le pool de threads. Si vous attendez des E / S, ou attendez un événement, etc., vous attachez ce thread de pool de threads et il ne peut être utilisé par personne d'autre. La même idée s'applique aux tâches de longue durée, bien que ce qui constitue une tâche de longue durée soit subjectif.
Pax Diablo fait également un bon point. Faire tourner des fils n'est pas gratuit. Cela prend du temps et ils consomment de la mémoire supplémentaire pour leur espace de pile. Le pool de threads réutilisera les threads pour amortir ce coût.
Remarque: vous avez demandé comment utiliser un thread de pool de threads pour télécharger des données ou effectuer des E / S de disque. Vous ne devez pas utiliser un thread de pool de threads pour cela (pour les raisons que j'ai décrites ci-dessus). Utilisez plutôt les E / S asynchrones (également appelées méthodes BeginXX et EndXX). Pour un
FileStream
ce seraitBeginRead
etEndRead
. Pour unHttpWebRequest
ce seraitBeginGetResponse
etEndGetResponse
. Ils sont plus compliqués à utiliser, mais ils constituent le bon moyen d'effectuer des E / S multithreads.la source
Méfiez-vous du pool de threads .NET pour les opérations qui peuvent bloquer pour toute partie significative, variable ou inconnue de leur traitement, car il est sujet à la famine des threads. Envisagez d'utiliser les extensions parallèles .NET, qui fournissent un bon nombre d'abstractions logiques sur les opérations threadées. Ils incluent également un nouveau planificateur, qui devrait être une amélioration de ThreadPool. Voir ici
la source
Une des raisons d'utiliser le pool de threads uniquement pour les petites tâches est qu'il existe un nombre limité de threads de pool de threads. Si l'un est utilisé pendant une longue période, il empêche ce thread d'être utilisé par un autre code. Si cela se produit plusieurs fois, le pool de threads peut être épuisé.
L'utilisation du pool de threads peut avoir des effets subtils - certains minuteurs .NET utilisent des threads de pool de threads et ne se déclenchent pas, par exemple.
la source
Si vous avez une tâche d'arrière-plan qui durera longtemps, comme pendant toute la durée de vie de votre application, créer votre propre thread est une chose raisonnable. Si vous avez des tâches courtes à effectuer dans un thread, utilisez le pool de threads.
Dans une application où vous créez de nombreux threads, la surcharge de création des threads devient substantielle. L'utilisation du pool de threads crée les threads une fois et les réutilise, évitant ainsi la surcharge de création de thread.
Dans une application sur laquelle j'ai travaillé, passer de la création de threads à l'utilisation du pool de threads pour les threads de courte durée a vraiment aidé à la mise en œuvre de l'application.
la source
Pour des performances optimales avec des unités exécutées simultanément, écrivez votre propre pool de threads, où un pool d'objets Thread est créé au démarrage et passe au blocage (anciennement suspendu), en attendant un contexte à exécuter (un objet avec une interface standard implémentée par votre code).
Tant d'articles sur Tâches vs Threads vs .NET ThreadPool ne vous donnent pas vraiment ce dont vous avez besoin pour prendre une décision en matière de performances. Mais quand vous les comparez, les Threads l'emportent et surtout un pool de Threads. Ils sont les meilleurs répartis sur les processeurs et démarrent plus rapidement.
Ce qui devrait être discuté est le fait que l'unité d'exécution principale de Windows (y compris Windows 10) est un thread et que la surcharge de changement de contexte du système d'exploitation est généralement négligeable. En termes simples, je n'ai pas été en mesure de trouver des preuves convaincantes de bon nombre de ces articles, que l'article revendique de meilleures performances en économisant le changement de contexte ou une meilleure utilisation du processeur.
Maintenant, pour un peu de réalisme:
La plupart d'entre nous n'auront pas besoin que notre application soit déterministe, et la plupart d'entre nous n'ont pas une expérience difficile avec les threads, ce qui, par exemple, vient souvent avec le développement d'un système d'exploitation. Ce que j'ai écrit ci-dessus n'est pas pour un débutant.
Le plus important est donc de discuter de ce qui est facile à programmer.
Si vous créez votre propre pool de threads, vous aurez un peu d'écriture à faire car vous devrez vous préoccuper du suivi de l'état d'exécution, comment simuler la suspension et la reprise, et comment annuler l'exécution - y compris dans une application à l'échelle fermer. Vous devrez peut-être également vous demander si vous souhaitez développer dynamiquement votre pool et quelle sera la limitation de capacité de votre pool. Je peux écrire un tel cadre en une heure, mais c'est parce que je l'ai fait tant de fois.
Le moyen le plus simple d'écrire une unité d'exécution est peut-être d'utiliser une tâche. La beauté d'une tâche est que vous pouvez en créer une et la lancer en ligne dans votre code (bien que la prudence puisse être justifiée). Vous pouvez transmettre un jeton d'annulation à gérer lorsque vous souhaitez annuler la tâche. En outre, il utilise l'approche de promesse pour chaîner les événements et vous pouvez lui faire renvoyer un type de valeur spécifique. De plus, avec async et await, plus d'options existent et votre code sera plus portable.
En substance, il est important de comprendre les avantages et les inconvénients de Tasks vs Threads vs .NET ThreadPool. Si j'ai besoin de hautes performances, je vais utiliser des threads et je préfère utiliser mon propre pool.
Un moyen simple de comparer est de démarrer 512 threads, 512 tâches et 512 threads ThreadPool. Vous trouverez un retard au début avec les threads (d'où pourquoi écrire un pool de threads), mais les 512 threads s'exécuteront dans quelques secondes tandis que les threads Tasks et .NET ThreadPool prennent jusqu'à quelques minutes pour démarrer.
Voici les résultats d'un tel test (i5 quad core avec 16 Go de RAM), donnant toutes les 30 secondes pour fonctionner. Le code exécuté effectue des E / S de fichier simples sur un lecteur SSD.
Résultats de test
la source
Les pools de threads sont parfaits lorsque vous avez plus de tâches à traiter que de threads disponibles.
Vous pouvez ajouter toutes les tâches à un pool de threads et spécifier le nombre maximum de threads pouvant s'exécuter à un moment donné.
Consultez cette page sur MSDN: http://msdn.microsoft.com/en-us/library/3dasc8as(VS.80).aspx
la source
Utilisez toujours un pool de threads si vous le pouvez, travaillez au plus haut niveau d'abstraction possible. Les pools de threads cachent la création et la destruction de threads pour vous, c'est généralement une bonne chose!
la source
La plupart du temps, vous pouvez utiliser le pool car vous évitez le processus coûteux de création du thread.
Toutefois, dans certains scénarios, vous souhaiterez peut-être créer un thread. Par exemple, si vous n'êtes pas le seul à utiliser le pool de threads et que le thread que vous créez est de longue durée (pour éviter de consommer des ressources partagées) ou par exemple si vous souhaitez contrôler la stacksize du thread.
la source
N'oubliez pas d'enquêter sur l'agent d'arrière-plan.
Je trouve que pour beaucoup de situations, cela me donne exactement ce que je veux sans le gros du travail.
À votre santé.
la source
J'utilise généralement le Threadpool chaque fois que j'ai besoin de faire quelque chose sur un autre thread et que je ne me soucie pas vraiment de son exécution ou de sa fin. Quelque chose comme la journalisation ou peut-être même le téléchargement d'un fichier en arrière-plan (bien qu'il existe de meilleures façons de le faire de manière asynchrone). J'utilise mon propre thread lorsque j'ai besoin de plus de contrôle. De plus, ce que j'ai trouvé, c'est d'utiliser une file d'attente Threadsafe (pirater la vôtre) pour stocker des "objets de commande", c'est bien quand j'ai plusieurs commandes sur lesquelles je dois travailler dans> 1 thread. Ainsi, vous pouvez diviser un fichier Xml et mettre chaque élément dans une file d'attente, puis plusieurs threads travaillent à effectuer un traitement sur ces éléments. J'ai écrit une telle file d'attente en uni (VB.net!) Que j'ai convertie en C #. Je l'ai inclus ci-dessous sans raison particulière (ce code peut contenir des erreurs).
la source
Je voulais un pool de threads pour distribuer le travail entre les cœurs avec le moins de latence possible, et cela ne devait pas bien fonctionner avec d'autres applications. J'ai trouvé que les performances du pool de threads .NET n'étaient pas aussi bonnes qu'elles pourraient l'être. Je savais que je voulais un thread par cœur, j'ai donc écrit ma propre classe de remplacement de pool de threads. Le code est fourni en tant que réponse à une autre question StackOverflow ici .
Quant à la question initiale, le pool de threads est utile pour diviser les calculs répétitifs en parties qui peuvent être exécutées en parallèle (en supposant qu'ils peuvent être exécutés en parallèle sans changer le résultat). La gestion manuelle des threads est utile pour des tâches telles que l'interface utilisateur et IO.
la source