Parallélisme des tâches (bibliothèque parallèle de tâches)

La bibliothèque parallèle de tâches, comme son nom l'indique, est basée sur le concept de tâche. Le terme parallélisme des tâches fait référence à une ou plusieurs tâches indépendantes qui s'exécutent simultanément. Une tâche représente une opération asynchrone et est similaire, à certains égards, à la création d'un nouveau thread ou d'un élément de travail ThreadPool, mais à un niveau d'abstraction supérieur. Les tâches présentent deux grands avantages :

  • Une utilisation plus efficace et évolutive des ressources système.

    En arrière-plan, les tâches sont mises en file d'attente dans le ThreadPool, amélioré au moyen d'algorithmes (tels que le « hill-climbing ») qui déterminent et s'ajustent au nombre de threads qui maximise le débit. Cela rend les tâches relativement simples et vous permet d'en créer de nombreuses pour un parallélisme affiné. En outre, des algorithmes de vol de travail très répandus sont employés pour fournir un équilibrage de charge.

  • Davantage de contrôle par programmation qu'avec un thread ou un élément de travail.

    Les tâches et l'infrastructure construites autour de ces algorithmes fournissent un ensemble riche d'API prenant en charge l'attente, l'annulation, les continuations, la gestion fiable des exceptions, l'état détaillé, la planification personnalisée, et bien plus encore.

Pour ces raisons, les tâches sont les API préférées pour l'écriture du code multithread, asynchrone et parallèle dans .NET Framework 4.

Création et exécution implicites de tâches

La méthode Parallel.Invoke offre un moyen pratique d'exécuter simultanément un nombre d'instructions arbitraires. Pour cela, passez un délégué Action pour chaque élément de travail. La façon la plus facile de créer ces délégués est d'utiliser des expressions lambda. L'expression lambda peut appeler une méthode nommée ou fournir du code inline. L'exemple suivant montre un appel Invoke de base qui crée et démarre deux tâches qui s'exécutent simultanément.

RemarqueRemarque

Cette documentation utilise des expressions lambda pour définir des délégués dans la bibliothèque parallèle de tâches.Si vous n'êtes pas familiarisé avec les expressions lambda en C# ou Visual Basic, consultez Expressions lambda en PLINQ et dans la bibliothèque parallèle de tâches.

Parallel.Invoke(Sub() DoSomeWork(), Sub() DoSomeOtherWork())
Parallel.Invoke(() => DoSomeWork(), () => DoSomeOtherWork());
RemarqueRemarque

Le nombre d'instances Task créées en arrière-plan par Invoke n'est pas nécessairement égal au nombre de délégués fournis.La bibliothèque parallèle de tâches peut utiliser différentes optimisations, surtout avec un grand nombre de délégués.

Pour plus d'informations, consultez Comment : utiliser Parallel.Invoke pour exécuter des opérations parallèles.

Pour un plus grand contrôle de l'exécution de tâches ou pour retourner une valeur à partir de la tâche, vous devez utiliser des objets Task de manière plus explicite.

Création et exécution explicites de tâches

Une tâche est représentée par la classe System.Threading.Tasks.Task. Une tâche qui retourne une valeur est représentée par la classe System.Threading.Tasks.Task<TResult>, qui hérite de Task. L'objet de tâche gère les détails de l'infrastructure et fournit des méthodes et des propriétés accessibles depuis le thread appelant pendant la durée de vie de la tâche. Par exemple, vous pouvez accéder à la propriété Status d'une tâche à tout moment pour déterminer si son exécution a commencé, est terminée, a été annulée ou a levé une exception. Le statut est représenté par une énumération TaskStatus.

Lorsque vous créez une tâche, vous lui donnez un délégué utilisateur qui encapsule le code que la tâche exécutera. Le délégué peut être exprimé en tant que délégué nommé, méthode anonyme ou expression lambda. Les expressions lambda peuvent contenir un appel à une méthode nommée, comme indiqué dans l'exemple suivant.

        ' Create a task and supply a user delegate by using a lambda expression.
        Dim taskA = New Task(Sub() Console.WriteLine("Hello from taskA."))

        ' Start the task.
        taskA.Start()

        ' Output a message from the joining thread.
        Console.WriteLine("Hello from the joining thread.")

        ' Output:
        ' Hello from the joining thread.
        ' Hello from taskA. 

            // Create a task and supply a user delegate by using a lambda expression.
            var taskA = new Task(() => Console.WriteLine("Hello from taskA."));

            // Start the task.
            taskA.Start();

            // Output a message from the joining thread.
            Console.WriteLine("Hello from the calling thread.");


            /* Output:
             * Hello from the joining thread.
             * Hello from taskA. 
             */

Vous pouvez également utiliser la méthode StartNew pour créer et lancer une tâche dans une opération. Il s'agit de la meilleure façon de créer et lancer des tâches si création et la planification n'ont pas besoin d'être séparées, comme l'illustre l'exemple suivant

' Better: Create and start the task in one operation.
Dim taskA = Task.Factory.StartNew(Sub() Console.WriteLine("Hello from taskA."))

' Output a message from the joining thread.
Console.WriteLine("Hello from the joining thread.")
// Create and start the task in one operation.
var taskA = Task.Factory.StartNew(() => Console.WriteLine("Hello from taskA."));

// Output a message from the joining thread.
Console.WriteLine("Hello from the joining thread.");

La tâche expose une propriété Factory statique qui retourne une instance par défaut de TaskFactory, afin que vous puissiez appeler la méthode en tant que Task.Factory.StartNew(…). De plus, dans cet exemple, parce que les tâches sont de type System.Threading.Tasks.Task<TResult>, chacune d'elle a une propriété Result publique contenant le résultat du calcul. Les tâches sont exécutées de façon asynchrone et peuvent se terminer dans n'importe quel ordre. Si vous accédez à la propriété Result avant la fin du calcul, la propriété se bloquera jusqu'à ce que la valeur soit disponible.

Dim taskArray() = {Task(Of Double).Factory.StartNew(Function() DoComputation1()),
                   Task(Of Double).Factory.StartNew(Function() DoComputation2()),
                   Task(Of Double).Factory.StartNew(Function() DoComputation3())}


Dim results() As Double
ReDim results(taskArray.Length)
For i As Integer = 0 To taskArray.Length
    results(i) = taskArray(i).Result
Next
Task<double>[] taskArray = new Task<double>[]
   {
       Task<double>.Factory.StartNew(() => DoComputation1()),

       // May be written more conveniently like this:
       Task.Factory.StartNew(() => DoComputation2()),
       Task.Factory.StartNew(() => DoComputation3())                
   };

double[] results = new double[taskArray.Length];
for (int i = 0; i < taskArray.Length; i++)
    results[i] = taskArray[i].Result;

Pour plus d'informations, consultez Comment : retourner une valeur à partir d'une tâche.

Lorsque vous utilisez une expression lambda pour créer le délégué d'une tâche, vous avez accès à toutes les variables qui sont visibles à ce stade dans votre code source. Toutefois, dans certains cas, notamment dans des boucles, une expression lambda ne capture pas la variable comme prévu. Elle capture uniquement la valeur finale, pas la valeur qui change au cours de chaque itération. Vous pouvez accéder à la valeur de chaque itération en fournissant un objet d'état à une tâche via son constructeur, comme l'illustre l'exemple suivant :


    Class MyCustomData

        Public CreationTime As Long
        Public Name As Integer
        Public ThreadNum As Integer
    End Class

    Sub TaskDemo2()
        ' Create the task object by using an Action(Of Object) to pass in custom data
        ' in the Task constructor. This is useful when you need to capture outer variables
        ' from within a loop. 
        ' As an experiement, try modifying this code to capture i directly in the lamda,
        ' and compare results.
        Dim taskArray() As Task
        ReDim taskArray(10)
        For i As Integer = 0 To taskArray.Length - 1
            taskArray(i) = New Task(Sub(obj As Object)
                                        Dim mydata = CType(obj, MyCustomData)
                                        mydata.ThreadNum = Thread.CurrentThread.ManagedThreadId
                                        Console.WriteLine("Hello from Task #{0} created at {1} running on thread #{2}.",
                                                          mydata.Name, mydata.CreationTime, mydata.ThreadNum)
                                    End Sub,
            New MyCustomData With {.Name = i, .CreationTime = DateTime.Now.Ticks}
            )
            taskArray(i).Start()
        Next

    End Sub


       class MyCustomData
       {
        public long CreationTime;
        public int Name;
        public int ThreadNum;
        }

    void TaskDemo2()
    {
        // Create the task object by using an Action(Of Object) to pass in custom data
        // in the Task constructor. This is useful when you need to capture outer variables
        // from within a loop. As an experiement, try modifying this code to 
        // capture i directly in the lambda, and compare results.
        Task[] taskArray = new Task[10];

        for(int i = 0; i < taskArray.Length; i++)
        {
            taskArray[i] = new Task((obj) =>
                {
                                        MyCustomData mydata = (MyCustomData) obj;
                                        mydata.ThreadNum = Thread.CurrentThread.ManagedThreadId;
                                        Console.WriteLine("Hello from Task #{0} created at {1} running on thread #{2}.",
                                                          mydata.Name, mydata.CreationTime, mydata.ThreadNum)
                },
            new MyCustomData () {Name = i, CreationTime = DateTime.Now.Ticks}
            );
            taskArray[i].Start();
        }
    }

Cet état est passé comme un argument au délégué de tâche et est accessible dans l'objet de tâche à l'aide de la propriété AsyncState. En outre, le passage des données via le constructeur peut procurer un léger avantage en termes de performances dans certains scénarios.

ID de tâche

Chaque tâche reçoit un ID d'entier qui l'identifie de façon unique dans un domaine d'application et est accessible à l'aide de la propriété Id. L'ID est utile pour la consultation des informations de tâche dans les fenêtres Piles parallèles et Tâches parallèles du débogueur Visual Studio. L'ID est créé de manière différée, ce qui signifie qu'il n'est pas créé tant que cela n'est pas demandé ; par conséquent, une tâche peut avoir un ID différent à chaque exécution du programme. Pour plus d'informations sur l'affichage des ID de tâche dans le débogueur, consultez Utilisation de la fenêtre Piles parallèles.

Options de création de tâches

La plupart des API qui créent des tâches fournissent des surcharges qui acceptent un paramètre TaskCreationOptions. En spécifiant l'une de ces options, vous indiquez au planificateur de tâches la manière de planifier la tâche dans le pool de threads. Le tableau suivant répertorie les différentes options de création de tâches.

Élément

Description

None

Option par défaut lorsqu'aucune option n'est spécifiée. Le planificateur utilise ses méthodes heuristiques par défaut pour planifier la tâche.

PreferFairness

Spécifie que la tâche doit être planifiée afin que les tâches créées précédemment soient susceptibles d'être exécutées plus tôt et que les tâches créées ultérieurement soient susceptibles d'être exécutées plus tard.

LongRunning

Spécifie que la tâche représente une opération de longue durée.

AttachedToParent

Spécifie qu'une tâche doit être créée en tant qu'enfant attaché à la tâche actuelle, s'il en existe une. Pour plus d'informations, consultez Tâches imbriquées et tâches enfants.

Les options peuvent être combinées avec une opération de bits OR. L'exemple suivant montre une tâche avec les options LongRunning et PreferFairness.


Dim task3 = New Task(Sub() MyLongRunningMethod(),
                        TaskCreationOptions.LongRunning Or TaskCreationOptions.PreferFairness)
task3.Start()
var task3 = new Task(() => MyLongRunningMethod(),
                    TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness);
task3.Start();

Création de continuations de tâches

Les méthodes Task.ContinueWith et Task<TResult>.ContinueWith vous permettent de spécifier une tâche devant être lancée lorsque l'antécédent est terminé. Une référence à l'antécédent est communiquée au délégué de la tâche de continuation pour qu'il puisse en examiner l'état. De plus, une transition entre antécédent et continuation peut être établie sous la forme d'une valeur définie par l'utilisateur dans la propriété Result, afin que la sortie de l'antécédent puisse servir d'entrée à la continuation. Dans l'exemple suivant, getData est lancé par le code du programme, puis, analyzeData est lancé automatiquement lorsque getData est terminé, et reportData est lancé lorsque analyzeData est terminé. getData produit comme résultat un tableau d'octets, passé dans analyzeData. analyzeData traite ce tableau et retourne un résultat dont le type est déduit du type de retour de la méthode Analyze. reportData prend l'entrée de analyzeData et produit un résultat dont le type est déduit de façon semblable et mis à disposition du programme dans la propriété Result.

        Dim getData As Task(Of Byte()) = New Task(Of Byte())(Function() GetFileData())
        Dim analyzeData As Task(Of Double()) = getData.ContinueWith(Function(x) Analyze(x.Result))
        Dim reportData As Task(Of String) = analyzeData.ContinueWith(Function(y As Task(Of Double)) Summarize(y.Result))

        getData.Start()

        System.IO.File.WriteAllText("C:\reportFolder\report.txt", reportData.Result)

            Task<byte[]> getData = new Task<byte[]>(() => GetFileData());
            Task<double[]> analyzeData = getData.ContinueWith(x => Analyze(x.Result));
            Task<string> reportData = analyzeData.ContinueWith(y => Summarize(y.Result));

            getData.Start();

            //or...
            Task<string> reportData2 = Task.Factory.StartNew(() => GetFileData())
                                        .ContinueWith((x) => Analyze(x.Result))
                                        .ContinueWith((y) => Summarize(y.Result));

            System.IO.File.WriteAllText(@"C:\reportFolder\report.txt", reportData.Result);



Les méthodes ContinueWhenAll et ContinueWhenAny vous permettent de continuer avec plusieurs tâches. Pour plus d'informations, consultez Tâches de continuation et Comment : chaîner plusieurs tâches avec des continuations.

Création de tâches imbriquées détachées

Lorsque le code utilisateur qui s'exécute dans une tâche crée une tâche sans spécifier l'option AttachedToParent, la nouvelle tâche n'est pas synchronisée avec la tâche externe. Ces tâches sont appelées tâches imbriquées détachées. L'exemple suivant montre une tâche qui crée une tâche imbriquée détachée.

Dim outer = Task.Factory.StartNew(Sub()
                                      Console.WriteLine("Outer task beginning.")
                                      Dim child = Task.Factory.StartNew(Sub()
                                                                            Thread.SpinWait(5000000)
                                                                            Console.WriteLine("Detached task completed.")
                                                                        End Sub)
                                  End Sub)
outer.Wait()
Console.WriteLine("Outer task completed.")

' Output:
'     Outer task beginning.
'     Outer task completed.
'    Detached child completed.
            var outer = Task.Factory.StartNew(() =>
            {
                Console.WriteLine("Outer task beginning.");

                var child = Task.Factory.StartNew(() =>
                {
                    Thread.SpinWait(5000000);
                    Console.WriteLine("Detached task completed.");
                });

            });

            outer.Wait();
            Console.WriteLine("Outer task completed.");

            /* Output:
                Outer task beginning.
                Outer task completed.
                Detached task completed.

             */

Notez que la tâche externe n'attend pas que la tâche imbriquée soit terminée.

Création de tâches enfants

Lorsque le code utilisateur qui s'exécute dans une tâche crée une tâche avec l'option AttachedToParent, la nouvelle tâche est une tâche enfant de la tâche d'origine, appelée tâche parent. Vous pouvez utiliser l'option AttachedToParent pour exprimer le parallélisme des tâches structuré, car la tâche parent attend implicitement que toutes les tâches enfants soient terminées. L'exemple suivant affiche une tâche qui crée une tâche enfant :

Dim parent = Task.Factory.StartNew(Sub()
                                       Console.WriteLine("Parent task beginning.")
                                       Dim child = Task.Factory.StartNew(Sub()
                                                                             Thread.SpinWait(5000000)
                                                                             Console.WriteLine("Attached child completed.")
                                                                         End Sub,
                                                                         TaskCreationOptions.AttachedToParent)

                                   End Sub)
outer.Wait()
Console.WriteLine("Parent task completed.")

' Output:
'     Parent task beginning.
'     Attached child completed.
'     Parent task completed.
var parent = Task.Factory.StartNew(() =>
{
    Console.WriteLine("Parent task beginning.");

    var child = Task.Factory.StartNew(() =>
    {
        Thread.SpinWait(5000000);
        Console.WriteLine("Attached child completed.");
    }, TaskCreationOptions.AttachedToParent);

});

parent.Wait();
Console.WriteLine("Parent task completed.");

/* Output:
    Parent task beginning.
    Attached task completed.
    Parent task completed.
 */

Pour plus d'informations, consultez Tâches imbriquées et tâches enfants.

Attente des tâches

Les types System.Threading.Tasks.Task et System.Threading.Tasks.Task<TResult> fournissent plusieurs surcharges d'une méthode Task.Wait et Task<TResult>.Wait qui vous permettent d'attendre qu'une tâche soit terminée. De plus, les surcharges des méthodes statiques Task.WaitAll et Task.WaitAny vous permettent d'attendre que certaines ou toutes les tâches soient terminées.

En général, il est nécessaire d'attendre une tâche pour l'une des raisons suivantes :

  • Le thread principal dépend du résultat final calculé par une tâche.

  • Vous devez gérer les exceptions pouvant être levées depuis la tâche.

L'exemple suivant affiche le modèle de base qui n'implique pas la gestion des exceptions.

Dim tasks() =
{
    Task.Factory.StartNew(Sub() MethodA()),
    Task.Factory.StartNew(Sub() MethodB()),
    Task.Factory.StartNew(Sub() MethodC())
}

' Block until all tasks complete.
Task.WaitAll(tasks)

' Continue on this thread...
Task[] tasks = new Task[3]
{
    Task.Factory.StartNew(() => MethodA()),
    Task.Factory.StartNew(() => MethodB()),
    Task.Factory.StartNew(() => MethodC())
};

//Block until all tasks complete.
Task.WaitAll(tasks);

// Continue on this thread...

Pour obtenir un exemple illustrant la gestion des exceptions, consultez Comment : gérer les exceptions levées par des tâches.

Certaines surcharges vous permettent de spécifier un délai d'attente, et d'autres prennent un CancellationToken supplémentaire en tant que paramètre d'entrée, afin que l'attente puisse être annulée soit par programmation, soit en réponse à l'entrée utilisateur.

Lorsque vous attendez une tâche, vous attendez implicitement tous les enfants de cette tâche créés à l'aide de l'option TaskCreationOptionsAttachedToParent. Task.Wait est retourné immédiatement si la tâche est déjà terminée. Toutes les exceptions déclenchées par une tâche seront levées par une méthode Wait, même si la méthode Wait a été appelée une fois la tâche terminée.

Pour plus d'informations, consultez Comment : attendre la fin d'une ou de plusieurs tâches.

Gestion des exceptions des tâches

Lorsqu'une tâche lève une ou plusieurs exceptions, les exceptions sont encapsulées dans un AggregateException. Cette exception est propagée vers le thread joint à la tâche, qui est en général le thread qui attend la tâche ou tente d'accéder à la propriété Result de la tâche. Ce comportement permet d'appliquer la stratégie .NET Framework selon laquelle toutes les exceptions non gérées doivent par défaut détruire le processus. Le code appelant peut gérer les exceptions en utilisant la méthode Wait, WaitAll ou WaitAny, ou la propriété Result() dans la tâche ou le groupe de tâches, et joindre la méthode Wait à un bloc try-catch.

Le thread joint peut également gérer des exceptions en accédant à la propriété Exception avant que la tâche ne soit récupérée par le garbage collector. En accédant à cette propriété, vous empêchez l'exception non gérée de déclencher le comportement de propagation de l'exception détruisant le processus lorsque l'objet est finalisé.

Pour plus d'informations sur les exceptions et les tâches, consultez Gestion des exceptions (bibliothèque parallèle de tâches) et Comment : gérer les exceptions levées par des tâches.

Annulation des tâches

La classe Task prend en charge l'annulation coopérative et s'intègre pleinement aux classes System.Threading.CancellationTokenSource et System.Threading.CancellationToken, nouvelles dans le .NET Framework version 4. De nombreux constructeurs de la classe System.Threading.Tasks.Task prennent un CancellationToken en tant que paramètre d'entrée. De nombreuses surcharges StartNew prennent également un CancellationToken.

Vous pouvez créer le jeton et la requête d'annulation ultérieurement, à l'aide de la classe CancellationTokenSource. Passez le jeton au Task en tant qu'argument et référencez ce même jeton dans votre délégué d'utilisateur, qui répond à une requête d'annulation. Pour plus d'informations, consultez Annulation de tâches et Comment : annuler une tâche et ses enfants.

Classe TaskFactory

La classe TaskFactory fournit des méthodes statiques qui encapsulent des modèles communs pour la création et le lancement des tâches et des tâches de continuation.

Le TaskFactory par défaut est accessible en tant que propriété statique dans la classe Task ou Task<TResult>. Vous pouvez également instancier directement un TaskFactory et spécifier différentes options qui incluent une option CancellationToken, TaskCreationOptions, TaskContinuationOptions ou TaskScheduler. Toutes les options spécifiées lors de la création de la fabrique de tâches seront appliquées à toutes les tâches qu'elle crée, à moins que la tâche ne soit créée à l'aide de l'énumération TaskCreationOptions, auquel cas les options de la tâche substituent celles de la fabrique de tâches.

Tâches sans délégués

Dans certains cas, vous pouvez utiliser un Task pour encapsuler une opération asynchrone exécutée par un composant externe au lieu de votre propre délégué utilisateur. Si l'opération est basée sur le modèle de programmation asynchrone Begin/End, vous pouvez utiliser les méthodes FromAsync. Si ce n'est pas le cas, vous pouvez utiliser l'objet TaskCompletionSource<TResult> pour encapsuler l'opération dans une tâche et, de cette façon, bénéficier de certains des avantages de programmabilité Task, comme par exemple, la prise en charge de la propagation et des continuations d'exceptions. Pour plus d'informations, consultez TaskCompletionSource<TResult>.

Planificateurs personnalisés

La plupart des développeurs d'applications ou de bibliothèques ne se soucient pas du processeur sur lequel s'exécute la tâche, ni de la manière dont il synchronise son travail avec d'autres tâches ou de la façon dont il est planifié sur le System.Threading.ThreadPool. Ils demandent simplement à ce qu'il s'exécute aussi efficacement que possible sur l'ordinateur hôte. Si vous avez besoin d'un contrôle plus affiné sur les détails de la planification, la bibliothèque parallèle de tâches vous permet de configurer des paramètres dans le planificateur de tâches par défaut et vous permet même de fournir un planificateur personnalisé. Pour plus d'informations, consultez TaskScheduler.

Structures de données associées

La bibliothèque parallèle de tâches possède plusieurs nouveaux types publics qui sont utiles dans les scénarios parallèles et séquentiels. Ces derniers incluent plusieurs classes de collection thread-safe, rapides et évolutives dans l'espace de noms System.Collections.Concurrent, et plusieurs nouveaux types de synchronisation, tels que SemaphoreLock et System.Threading.ManualResetEventSlim, qui sont plus efficaces que leurs prédécesseurs pour certains genres de charges de travail. D'autres types nouveaux du .NET Framework version 4, tels que System.Threading.Barrier et System.Threading.SpinLock, fournissent des fonctionnalités qui n'étaient pas disponibles dans les versions précédentes. Pour plus d'informations, consultez Structures de données pour la programmation parallèle.

Types de tâches personnalisés

Nous vous recommandons de ne pas hériter de System.Threading.Tasks.Task ou System.Threading.Tasks.Task<TResult>. Utilisez plutôt la propriété AsyncState pour associer d'autres données ou états à un objet Task ou Task<TResult>. Vous pouvez également utiliser des méthodes d'extension pour étendre les fonctionnalités des classes Task et Task<TResult>. Pour plus d'informations sur les méthodes d'extension, consultez Méthodes d'extension (Guide de programmation C#) et Méthodes d'extension (Visual Basic).

Si vous devez hériter de Task ou Task<TResult>, vous ne pouvez pas utiliser les classes System.Threading.Tasks.TaskFactory, System.Threading.Tasks.TaskFactory<TResult> ou System.Threading.Tasks.TaskCompletionSource<TResult> créer des instances de votre tâche personnalisée parce que ces classes créent uniquement des objets Task et Task<TResult>. En outre, vous ne pouvez pas utiliser les mécanismes de continuation des tâches fournis par Task, Task<TResult>TaskFactory et TaskFactory<TResult> pour créer des instances de votre type de tâche personnalisé parce que ces mécanismes créent également uniquement des objets Task et Task<TResult>.

Rubriques connexes

Titre

Description

Tâches de continuation

Décrit le fonctionnement des continuations.

Tâches imbriquées et tâches enfants

Décrit la différence entre les tâches enfants et les tâches imbriquées.

Annulation de tâches

Décrit la prise en charge de l'annulation intégrée dans la classe Task.

Gestion des exceptions (bibliothèque parallèle de tâches)

Décrit comment les exceptions sur les threads simultanés sont gérées.

Comment : utiliser Parallel.Invoke pour exécuter des opérations parallèles

Explique comment utiliser Invoke.

Comment : retourner une valeur à partir d'une tâche

Décrit comment retourner des valeurs à partir de tâches.

Comment : attendre la fin d'une ou de plusieurs tâches

Décrit comment attendre des tâches.

Comment : annuler une tâche et ses enfants

Décrit comment annuler des tâches.

Comment : gérer les exceptions levées par des tâches

Décrit comment gérer les exceptions levées par des tâches.

Comment : chaîner plusieurs tâches avec des continuations

Décrit comment exécuter une tâche lorsqu'une autre tâche se termine.

Comment : parcourir une arborescence binaire avec des tâches parallèles

Décrit comment utiliser des tâches pour parcourir un arbre binaire.

Parallélisme de données (bibliothèque parallèle de tâches)

Décrit comment utiliser For et ForEach pour créer des boucles parallèles sur des données.

Programmation parallèle dans le .NET Framework

Nœud de niveau supérieur pour la programmation parallèle .NET.

Voir aussi

Concepts

Programmation parallèle dans le .NET Framework

Historique des modifications

Date

Historique

Motif

Mars 2011

Informations supplémentaires sur la manière d'hériter des classes Task et Task<TResult>.

Améliorations apportées aux informations.