Quand utiliser thread pool en C#?

j'ai essayé d'apprendre la programmation multi-threadée en C# et je suis confus au sujet du moment où il est préférable d'utiliser une piscine de thread vs. créer mes propres threads. Un livre recommande d'utiliser un pool de threads pour les petites tâches seulement (peu importe ce que cela signifie), Mais je ne semble pas trouver de vraies lignes directrices. Quelles sont les considérations que vous utilisez pour prendre cette décision en matière de programmation?

123
demandé sur participant 2008-09-28 10:00:10

15 réponses

si vous avez beaucoup de tâches logiques qui nécessitent un traitement constant et que vous voulez que cela soit fait en parallèle, utilisez le pool+scheduler.

si vous avez besoin de faire vos tâches liées aux IO en même temps, comme télécharger des trucs à partir de serveurs distants ou d'accès disque, mais avez besoin de le faire dire toutes les quelques minutes, puis faites vos propres threads et les tuer une fois que vous avez terminé.

Edit: au sujet de certaines considérations, j'utilise des piscines de thread pour la base de données accès, physique / simulation, AI (jeux), et pour les tâches scriptées a couru sur des machines virtuelles qui traitent beaucoup de tâches définies par l'utilisateur.

normalement un pool se compose de 2 threads par processeur (donc probablement 4 aujourd'hui), cependant vous pouvez configurer la quantité de threads que vous voulez, si vous savez combien vous avez besoin.

Edit: la raison pour faire vos propres threads est à cause des changements de contexte, (thats quand les threads ont besoin d'échanger Dans et hors du processus, avec leur mémoire.) Avoir des changements de contexte inutiles, disons quand vous n'utilisez pas vos threads, juste les laisser s'asseoir autour comme on pourrait dire, peut facilement la moitié de la performance de votre programme (dire que vous avez 3 threads de sommeil et 2 threads actifs). Ainsi, si ces threads de téléchargement sont en attente, ils mangent des tonnes de CPU et rafraîchissent le cache pour votre application réelle

44
répondu Robert Gould 2009-01-13 14:26:45

je vous suggérerais d'utiliser un thread pool en C# pour les mêmes raisons que n'importe quelle autre langue.

lorsque vous voulez limiter le nombre de threads en cours d'exécution ou que vous ne voulez pas avoir à les créer et les détruire, utilisez un pool de threads.

par petites tâches, le livre que vous lisez signifie tâches avec une courte durée de vie. Si cela prend dix secondes pour créer un thread qui ne tourne que pendant une seconde, c'est un endroit où vous devriez utiliser des piscines (ignorez mon les chiffres réels, c'est le ratio qui compte).

autrement, vous passez la majeure partie de votre temps à créer et à détruire des fils plutôt que de simplement faire le travail qu'ils sont censés faire.

47
répondu paxdiablo 2009-06-26 08:35:49

voici un bon résumé du pool de thread dans .Net: http://blogs.msdn.com/pedram/archive/2007/08/05/dedicated-thread-or-a-threadpool-thread.aspx

le post a également quelques points sur quand vous ne devriez pas utiliser le pool de thread et démarrer votre propre thread à la place.

28
répondu Franci Penov 2008-09-28 06:13:51

je recommande vivement la lecture de cet e-book gratuit: Thread en C# par Joseph Albahari

au moins lisez la section" pour commencer". L'e-book fournit une excellente introduction et comprend une foule de renseignements avancés sur le filetage.

savoir s'il faut ou non utiliser le pool de fils n'est qu'un début. Ensuite, vous aurez besoin de déterminer quelle méthode d'entrer dans la piscine de thread convient le mieux à vos besoins:

  • Task Parallel Library (.net Framework 4,0)
  • pool de threads.QueueUserWorkItem
  • Délégués Asynchrones
  • BackgroundWorker

cet e-book explique tout cela et conseille quand les utiliser vs. créer votre propre fil.

14
répondu jrupe 2010-09-29 14:09:37

le pool de threads est conçu pour réduire la commutation de contexte entre vos threads. Considérons un processus qui comporte plusieurs composants en cours d'exécution. Chacun de ces composants pourrait être la création de fils ouvriers. Plus de threads dans votre processus, plus de temps est perdu sur la commutation de contexte.

maintenant, si chacun de ces composants étaient la file d'attente d'articles à la piscine de thread, vous auriez beaucoup moins de commutation de contexte overhead.

le bassin de filetage est conçu pour maximisez le travail effectué sur vos CPU (ou vos cœurs CPU). C'est pourquoi, par défaut, le pool de thread tourne plusieurs threads par processeur.

il y a des situations où vous ne voulez pas utiliser le pool de threads. Si vous attendez sur l'entrée/sortie, ou en attente sur un événement, etc alors vous attachez ce fil de piscine fil et il ne peut pas être utilisé par quelqu'un 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. Tourner fils n'est pas libre. Cela prend du temps et ils consomment de la mémoire supplémentaire pour leur espace de stockage. Le pool de threads réutilisera les threads pour amortir ce coût.

Note: Vous avez demandé à propos de l'utilisation d'un thread pool thread pour télécharger des données ou effectuer des I/O disque.vous ne devriez pas utiliser un thread pool thread pour cela (pour les raisons que j'ai décrites ci-dessus). Utilisez plutôt l'E/S asynchrone (Alias les méthodes BeginXX et EndXX). Pour un FileStream qui serait BeginRead et EndRead . Pour un HttpWebRequest qui serait BeginGetResponse et EndGetResponse . Ils sont plus compliqués à utiliser, mais ils sont la bonne façon d'exécuter multi-threaded I/O.

8
répondu Brannon 2008-09-28 08:01:30

méfiez-vous du pool de threads .NET pour les opérations qui peuvent bloquer toute partie significative, variable ou inconnue de leur traitement, car il est sujet à la privation de threads. Envisagez d'utiliser les extensions parallèles .NET, qui fournissent un bon nombre d'abstractions logiques sur des opérations filetées. Ils comprennent également un nouvel ordonnanceur, qui devrait être une amélioration sur ThreadPool. Voir ici

6
répondu mancaus 2008-09-30 10:59:15

une raison d'utiliser le pool de threads pour les petites tâches seulement est qu'il y a un nombre limité de threads de pool de threads. Si l'un est utilisé pendant une longue période, Alors il empêche ce thread d'être utilisé par un autre code. Si cela se produit plusieurs fois alors le pool de thread peut s'épuiser.

utiliser le pool de threads peut avoir des effets subtils - certains.les minuteries net utilisent des threads de threads et ne se déclenchent pas, par exemple.

3
répondu Thomas Bratt 2008-09-28 13:38:32

pour la plus haute performance avec des unités d'exécution simultanées, écrivez votre propre pool de threads, où un pool d'objets threads sont créés au démarrage et vont 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 les tâches vs. Threads vs. The.Net ThreadPool ne parviennent pas à vous donner vraiment ce dont vous avez besoin pour prendre une décision pour la performance. Mais quand vous les comparez, Threads gagne dehors et surtout un bassin de fils. Ils sont distribués le mieux à travers les CPU et ils démarrent plus rapidement.

ce qui doit être discuté est le fait que L'unité d'exécution principale de Windows (y compris Windows 10) est un thread, et la commutation de contexte OS overhead est généralement négligeable. En termes simples, je n'ai pas été en mesure de trouver des preuves convaincantes de beaucoup de ces articles, si l'article réclame une performance plus élevée en économisant la commutation de contexte ou une meilleure utilisation CPU.

Maintenant, pour un peu de réalisme:

la plupart d'entre nous n'auront pas besoin de notre application pour être déterministe, et la plupart d'entre nous n'ont pas un arrière-plan dur avec des fils, 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.

donc ce qui peut être le plus important est de discuter de ce qui est facile à programmer.

si vous créez votre propre thread pool, vous aurez un peu d'écriture pour faire comme vous aurez besoin d'être concerné par le 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-wide shut down. Vous pourriez également avoir à se préoccuper de savoir si vous voulez faire croître votre piscine de façon dynamique et aussi quelle limitation de capacité votre piscine aura. Je peux écrire un tel cadre en une heure mais c'est parce que je l'ai fait tellement de fois.

peut-être la façon la plus simple d'écrire une unité d'exécution est de l'utilisation d'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 passer un token d'annulation à gérer lorsque vous voulez annuler la tâche. De plus, il utilise l'approche de la promesse pour enchaîner des événements, et vous pouvez lui faire retourner un type spécifique de valeur. De plus, avec async et en attente, plus d'options existent et votre code sera plus portable.

En fait, il est important de comprendre les avantages et les inconvénients avec des Tâches vs Fils contre le .NET pool de threads. Si j'ai besoin de hautes performances, je vais utiliser des threads, et je préfère utiliser ma propre piscine.

une façon facile de comparer est de démarrer 512 Threads, 512 Tasks, et 512 ThreadPool threads. Vous trouverez un retard au début avec les Threads (donc, pourquoi écrire un pool de threads), mais tous les 512 Threads seront lancés en quelques secondes tandis que les tâches et les threads.net ThreadPool prendront quelques minutes pour démarrer.

Ci-dessous les résultats d'un tel test (i5 Quad core avec 16 Go de RAM), donnant à chaque 30 secondes de course. Le code exécuté exécute simple file I / O sur un lecteur SSD.

Résultats Des Essais

2
répondu Grabe 2017-04-27 15:42:54
Les pools de threads

sont parfaits lorsque vous avez plus de tâches à traiter que les threads disponibles.

vous pouvez ajouter toutes les tâches à un pool de threads et spécifier le nombre maximum de threads qui peuvent s'exécuter à un certain moment.

Check out ce page sur MSDN: http://msdn.microsoft.com/en-us/library/3dasc8as (VS.80).aspx

1
répondu lajos 2008-09-28 06:07:46

utilisez toujours un pool de threads si vous le pouvez, travaillez au plus haut niveau d'abstraction possible. Les mares de fil se cachent en créant et en détruisant des fils pour vous, c'est généralement une bonne chose!

1
répondu JeffFoster 2008-09-28 06:08:25

la plupart du temps, vous pouvez utiliser la piscine que vous évitez le processus coûteux de créer le fil.

cependant dans certains scénarios vous pouvez vouloir 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 voulez contrôler la stacksize du thread.

1
répondu antonio 2008-09-28 08:01:06

si vous avez une tâche de fond qui durera longtemps, comme pour toute la vie de votre application, alors créer votre propre thread est une chose raisonnable. Si vous avez des travaux courts qui doivent être faits dans un thread, puis utiliser la mise en commun de thread.

dans une application où vous créez de nombreux threads, la hauteur de création des threads devient substantielle. L'utilisation de la piscine de fil crée les fils une fois et les réutilise, évitant ainsi le fil création de surcharge.

dans une application sur laquelle j'ai travaillé, en passant de la création de threads à l'utilisation de la piscine de threads pour les threads de courte durée vraiment helped la mise à travers de l'application.

1
répondu Bill 2009-01-13 14:21:02

n'oubliez pas d'enquêter sur le travailleur D'arrière-plan.

je trouve pour beaucoup de situations, il me donne juste ce que je veux sans le levage lourd.

santé.

1
répondu SetiSeeker 2009-06-26 05:48:24

j'utilise habituellement le Threadpool chaque fois que j'ai besoin de faire quelque chose sur un autre fil et ne se soucient pas vraiment quand il court ou se termine. Quelque chose comme la journalisation ou peut-être même le téléchargement d'un fichier en arrière-plan (bien qu'il y ait de meilleures façons de le faire dans le style async). J'utilise mon propre fil quand j'ai besoin de plus de contrôle. Aussi ce que j'ai trouvé est d'utiliser une file D'attente Threadsafe (hack your own) pour stocker des "objets de commande" est agréable quand j'ai plusieurs commandes que je dois travailler dans >1 thread. Donc, si vous voulez peut fractionner un fichier Xml et mettre chaque élément dans une file d'attente et ensuite avoir plusieurs threads travaillant sur faire un certain traitement sur ces éléments. J'ai écrit une telle file d'attente chemin du retour dans l'uni (VB.net!) que j'ai converti en C#. Je l'ai inclus ci-dessous pour aucune raison particulière (ce code peut contenir quelques erreurs).

using System.Collections.Generic;
using System.Threading;

namespace ThreadSafeQueue {
    public class ThreadSafeQueue<T> {
        private Queue<T> _queue;

        public ThreadSafeQueue() {
            _queue = new Queue<T>();
        }

        public void EnqueueSafe(T item) {
            lock ( this ) {
                _queue.Enqueue(item);
                if ( _queue.Count >= 1 )
                    Monitor.Pulse(this);
            }
        }

        public T DequeueSafe() {
            lock ( this ) {
                while ( _queue.Count <= 0 )
                    Monitor.Wait(this);

                return this.DeEnqueueUnblock();

            }
        }

        private T DeEnqueueUnblock() {
            return _queue.Dequeue();
        }
    }
}
0
répondu noocyte 2008-10-16 13:42:47

je voulais un pool de threads pour distribuer le travail à travers les cœurs avec le moins de latence possible, et qui n'ont pas eu à bien jouer avec d'autres applications. J'ai découvert que la performance de thread pool de .net n'était pas aussi bonne qu'elle pourrait l'être. Je savais que je voulais un fil par coeur, donc j'ai écrit ma propre classe de remplacement de piscine de fil. Le code est fourni en réponse à une autre question sur le débordement des piles ici .

quant à la question originale, le fil pool est utile pour fractionner les calculs répétitifs en parties qui peuvent être exécutées en parallèle (en supposant qu'elles puissent être exécutées en parallèle sans changer le résultat). La gestion manuelle du thread est utile pour des tâches comme UI et IO.

0
répondu cdiggins 2017-05-23 12:02:19