Exporter (0) Imprimer
Développer tout
Cet article a fait l'objet d'une traduction automatique. Déplacez votre pointeur sur les phrases de l'article pour voir la version originale de ce texte. Informations supplémentaires.
Traduction
Source

Pool de threads managés

La classe ThreadPool fournit à votre application un pool de threads de travail qui sont managés par le système, vous permettant de vous concentrer sur les tâches de l'application plutôt que sur la gestion des threads. Dans le cas de petites tâches qui exigent un traitement en arrière-plan, le pool de threads managé représente un moyen facile de tirer parti de plusieurs threads. Par exemple, en commençant par .NET Framework 4, vous pouvez créer les objets Task et Task<TResult>, qui effectuent des tâches asynchrones sur des threads de pool de threads.

Remarque Remarque

Démarrant avec le .NET Framework 2.0 Service Pack 1, le débit du pool de threads est amélioré considérablement dans les trois zones clés identifiées comme goulots d'étranglement dans les version finale précédentes du .NET Framework: mettre en file d'attente des tâches, distribuer des threads ThreadPool, et distribuer des threads de terminaison d'E/S. Pour utiliser cette fonctionnalité, votre application doit cibler le .NET Framework 3.5 ou une version ultérieure.

Pour les tâches en arrière-plan qui interagissent avec l'interface utilisateur, le .NET Framework version 2.0 fournit également la classe BackgroundWorker qui communique à l'aide d'événements déclenchés sur le thread d'interface utilisateur.

Le .NET Framework utilise des threads du pool de threads dans de nombreuses circonstances, notamment pour la terminaison des E/S asynchrones, les rappels de la minuterie, les opérations d'attente inscrites, les appels de méthodes asynchrones utilisant des délégués, et des connexions de socket System.Net.

Il existe plusieurs scénarios où il est plus approprié de créer et gérer vos propres threads au lieu d'utiliser les threads du pool de threads :

  • Vous avez besoin d'un thread de premier plan.

  • Il est nécessaire que le thread ait une priorité particulière.

  • Certaines tâches provoquent le blocage du thread pendant de longues périodes. Le pool de threads ayant un nombre maximal de threads, un grand nombre de threads bloqués dans le pool peut empêcher le démarrage de tâches.

  • Vous devez placer des threads dans un thread cloisonné (STA, Single-Threaded Apartment). Tous les threads de ThreadPool sont dans le MTA (Multithreaded Apartment).

  • Une identité stable doit être associée au thread ou un thread doit être dédié à une tâche.

Les threads du pool de threads sont des threads d'arrière-plan. Consultez Threads de premier plan et d'arrière-plan. Chaque thread utilise la taille de pile et l'ordre de priorité d'exécution par défaut. Il se trouve dans le MTA (Multithreaded Apartment).

Il existe un seul pool de threads par processus.

0ka9477y.collapse_all(fr-fr,VS.110).gifExceptions dans les threads d'un pool de threads

Les exceptions non gérées sur les threads du pool de threads mettent un terme au processus. Il existe trois exceptions à cette règle :

  • Un ThreadAbortException est levé dans un thread de pool de threads en raison d'un appel à Abort.

  • Un AppDomainUnloadedException est levé dans un thread du pool de threads, 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, consultez Exceptions dans les threads managés.

Remarque Remarque

Dans les versions 1.0 et 1.1 du .NET Framework, le Common Language Runtime intercepte en mode silencieux les exceptions non gérées dans les threads du pool de threads. Cela peut endommager l'état de l'application et éventuellement provoquer le blocage des applications, ce qui peut être très difficile à déboguer.

0ka9477y.collapse_all(fr-fr,VS.110).gifNombre maximal de threads de pool de threads

Le nombre des opérations qui peuvent être mises en file d'attente dans le pool de threads est limité uniquement par la mémoire disponible ; toutefois, le pool de threads limite le nombre de threads simultanément actifs dans le processus. En commençant par .NET Framework 4, la taille par défaut du pool de threads pour un processus dépend de plusieurs facteurs, tels que la taille de l'espace d'adressage virtuel. Un processus peut appeler la méthode GetMaxThreads pour déterminer le nombre de threads.

Vous pouvez contrôler le nombre maximal de threads en utilisant les méthodes GetMaxThreads et SetMaxThreads.

Remarque Remarque

Dans les versions 1.0 et 1.1 du .NET Framework, la taille du pool de threads ne peut pas être définie à partir du code managé. Le code qui héberge le Common Language Runtime peut définir cette taille à l'aide de CorSetMaxThreads, défini dans mscoree.h.

0ka9477y.collapse_all(fr-fr,VS.110).gifValeurs minimales du pool de threads

Le pool de threads fournit de nouveaux threads de travail ou threads de terminaison d'E/S à la demande jusqu'à ce qu'il atteigne un minimum spécifié pour chaque catégorie. Vous pouvez utiliser la méthode GetMinThreads pour obtenir ces valeurs minimales.

Remarque Remarque

Lorsqu'une demande est faible, le nombre réel de threads de pool de threads peut tomber en dessous des valeurs minimales.

Lorsqu'une valeur minimale est atteinte, le pool de threads peut créer des threads supplémentaires ou attendre que certaines tâches s'achèvent. En commençant par .NET Framework 4, le pool de threads crée et détruit des threads de travail afin d'optimiser le débit, qui est défini en tant que nombre de tâches qui s'achèvent par unité de temps. Un nombre insuffisant de threads risque d'empêcher une utilisation optimale des ressources disponibles, tandis qu'un trop grand nombre de threads peut augmenter le conflit de ressources.

Mise en garde Attention

Vous pouvez utiliser la méthode SetMinThreads pour augmenter le nombre minimal de threads inactifs. Toutefois, augmenter inutilement ces valeurs peut provoquer des problèmes de performances. Si un trop grand nombre de tâches démarrent en même temps, elles risquent toutes de s'exécuter avec lenteur. Dans la plupart des cas, le pool de threads sera plus performant avec son propre algorithme pour allouer des threads.

Le pool de threads fournit également les ThreadPool.UnsafeQueueUserWorkItem et méthodes ThreadPool.UnsafeRegisterWaitForSingleObject. Utilisez ces méthodes uniquement lorsque vous êtes certain que la pile de l'appelant n'est pas concernée par toutes les vérifications de sécurité effectuées pendant l'exécution de la tâche en file d'attente. QueueUserWorkItem et RegisterWaitForSingleObject capturent toutes deux la pile de l'appelant, qui est fusionnée dans la pile du thread du pool de threads lorsque le thread commence à exécuter une tâche. Si une vérification de la sécurité est nécessaire, l'ensemble de la pile doit être vérifié. Bien que la vérification assure la sécurité, cette vérification s'effectue au détriment des performances.

En commençant par .NET Framework 4, la façon la plus simple d'utiliser le pool de threads est d'utiliser Bibliothèque parallèle de tâches. Par défaut, les types parallèles de bibliothèque tels que Task et Task<TResult> utilisent des threads de pool de threads pour exécuter les tâches. Vous pouvez également utiliser le pool de threads en appelant ThreadPool.QueueUserWorkItem à partir du code managé (ou CorQueueUserWorkItem à partir du code non managé) et en passant un délégué WaitCallback représentant la méthode qui exécute la tâche. Une autre façon d'utiliser le pool de threads est de placer en file d'attente les éléments de travail liés à une opération d'attente en utilisant la méthode ThreadPool.RegisterWaitForSingleObject et en passant un WaitHandle qui, une fois signalé ou expiré, appelle la méthode représentée par le délégué WaitOrTimerCallback. Les threads de pools de threads sont utilisés pour appeler des méthodes de rappel.

Les exemples de code de cette section présentent le pool de threads à l'aide de la classe Task et des méthodes ThreadPool.QueueUserWorkItem et ThreadPool.RegisterWaitForSingleObject.

0ka9477y.collapse_all(fr-fr,VS.110).gifExécution de tâches asynchrones avec la bibliothèque parallèle de tâches

L'exemple suivant indique comment créer et utiliser un objet Task en appelant la méthode TaskFactory.StartNew. Pour obtenir un exemple qui utilise la classe Task<TResult> pour retourner une valeur à partir d'une tâche asynchrone, consultez Comment : retourner une valeur à partir d'une tâche.


// Demonstrated features:
//		Task ctor()
// 		Task.Factory
//		Task.Wait()
//		Task.RunSynchronously()
// Expected results:
// 		Task t1 (alpha) is created unstarted.
//		Task t2 (beta) is created started.
//		Task t1's (alpha) start is held until after t2 (beta) is started.
//		Both tasks t1 (alpha) and t2 (beta) are potentially executed on 
//           threads other than the main thread on multi-core machines.
//		Task t3 (gamma) is executed synchronously on the main thread.
using System;
using System.Threading;
using System.Threading.Tasks;

class StartNewDemo
{
    static void Main()
    {
        Action<object> action = (object obj) =>
        {
            Console.WriteLine("Task={0}, obj={1}, Thread={2}", 
                              Task.CurrentId, obj.ToString(), 
                              Thread.CurrentThread.ManagedThreadId);
        };

        // Construct an unstarted task
        Task t1 = new Task(action, "alpha");

        // Cosntruct a started task
        Task t2 = Task.Factory.StartNew(action, "beta");

        // Block the main thread to demonstate that t2 is executing
        t2.Wait();

        // Launch t1 
        t1.Start();

        Console.WriteLine("t1 has been launched. (Main Thread={0})", 
                          Thread.CurrentThread.ManagedThreadId);

        // Wait for the task to finish.
        // You may optionally provide a timeout interval or a cancellation token
        // to mitigate situations when the task takes too long to finish.
        t1.Wait();

        // Construct an unstarted task
        Task t3 = new Task(action, "gamma");

        // Run it synchronously
        t3.RunSynchronously();

        // Although the task was run synchronously, it is a good practice
        // to wait for it in the event exceptions were thrown by the task.
        t3.Wait();
    }
}


0ka9477y.collapse_all(fr-fr,VS.110).gifExécution de code de façon asynchrone avec QueueUserWorkItem

L'exemple suivant met en file d'attente une tâche très simple représentée par la méthode ThreadProc, en utilisant la méthode QueueUserWorkItem.


using System;
using System.Threading;

public class Example
{
    public static void Main()
    {
        // Queue the task.
        ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));

        Console.WriteLine("Main thread does some work, then sleeps.");
        // If you comment out the Sleep, the main thread exits before
        // the thread pool task runs.  The thread pool uses background
        // threads, which do not keep the application running.  (This
        // is a simple example of a race condition.)
        Thread.Sleep(1000);

        Console.WriteLine("Main thread exits.");
    }

    // This thread procedure performs the task.
    static void ThreadProc(Object stateInfo)
    {
        // No state object was passed to QueueUserWorkItem, so
        // stateInfo is null.
        Console.WriteLine("Hello from the thread pool.");
    }
}


0ka9477y.collapse_all(fr-fr,VS.110).gifIndication des données de tâche pour QueueUserWorkItem

L'exemple de code suivant utilise la méthode QueueUserWorkItem pour mettre une tâche en file d'attente et fournir les données pour cette tâche.


using System;
using System.Threading;

// TaskInfo holds state information for a task that will be
// executed by a ThreadPool thread.
public class TaskInfo
{
    // State information for the task.  These members
    // can be implemented as read-only properties, read/write
    // properties with validation, and so on, as required.
    public string Boilerplate;
    public int Value;

    // Public constructor provides an easy way to supply all
    // the information needed for the task.
    public TaskInfo(string text, int number)
    {
        Boilerplate = text;
        Value = number;
    }
}

public class Example
{
    public static void Main()
    {
        // Create an object containing the information needed
        // for the task.
        TaskInfo ti = new TaskInfo("This report displays the number {0}.", 42);

        // Queue the task and data.
        if (ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), ti))
        {
            Console.WriteLine("Main thread does some work, then sleeps.");

            // If you comment out the Sleep, the main thread exits before
            // the ThreadPool task has a chance to run.  ThreadPool uses
            // background threads, which do not keep the application
            // running.  (This is a simple example of a race condition.)
            Thread.Sleep(1000);

            Console.WriteLine("Main thread exits.");
        }
        else
        {
            Console.WriteLine("Unable to queue ThreadPool request.");
        }
    }

    // The thread procedure performs the independent task, in this case
    // formatting and printing a very simple report.
    //
    static void ThreadProc(Object stateInfo)
    {
        TaskInfo ti = (TaskInfo) stateInfo;
        Console.WriteLine(ti.Boilerplate, ti.Value);
    }
}


0ka9477y.collapse_all(fr-fr,VS.110).gifUtilisation de RegisterWaitForSingleObject

L'exemple suivant illustre plusieurs fonctionnalités de threading :


using System;
using System.Threading;

// TaskInfo contains data that will be passed to the callback
// method.
public class TaskInfo
{
    public RegisteredWaitHandle Handle = null;
    public string OtherInfo = "default";
}

public class Example
{
    public static void Main(string[] args)
    {
        // The main thread uses AutoResetEvent to signal the
        // registered wait handle, which executes the callback
        // method.
        AutoResetEvent ev = new AutoResetEvent(false);

        TaskInfo ti = new TaskInfo();
        ti.OtherInfo = "First task";
        // The TaskInfo for the task includes the registered wait
        // handle returned by RegisterWaitForSingleObject.  This
        // allows the wait to be terminated when the object has
        // been signaled once (see WaitProc).
        ti.Handle = ThreadPool.RegisterWaitForSingleObject(
            ev,
            new WaitOrTimerCallback(WaitProc),
            ti,
            1000,
            false );

        // The main thread waits three seconds, to demonstrate the
        // time-outs on the queued thread, and then signals.
        Thread.Sleep(3100);
        Console.WriteLine("Main thread signals.");
        ev.Set();

        // The main thread sleeps, which should give the callback
        // method time to execute.  If you comment out this line, the
        // program usually ends before the ThreadPool thread can execute.
        Thread.Sleep(1000);
        // If you start a thread yourself, you can wait for it to end
        // by calling Thread.Join.  This option is not available with
        // thread pool threads.
    }

    // The callback method executes when the registered wait times out,
    // or when the WaitHandle (in this case AutoResetEvent) is signaled.
    // WaitProc unregisters the WaitHandle the first time the event is
    // signaled.
    public static void WaitProc(object state, bool timedOut)
    {
        // The state object must be cast to the correct type, because the
        // signature of the WaitOrTimerCallback delegate specifies type
        // Object.
        TaskInfo ti = (TaskInfo) state;

        string cause = "TIMED OUT";
        if (!timedOut)
        {
            cause = "SIGNALED";
            // If the callback method executes because the WaitHandle is
            // signaled, stop future execution of the callback method
            // by unregistering the WaitHandle.
            if (ti.Handle != null)
                ti.Handle.Unregister(null);
        }

        Console.WriteLine("WaitProc( {0} ) executes on thread {1}; cause = {2}.",
            ti.OtherInfo,
            Thread.CurrentThread.GetHashCode().ToString(),
            cause
        );
    }
}


Ajouts de la communauté

AJOUTER
Afficher:
© 2014 Microsoft