Différences entre les tâches et les threads [dupliquer]

cette question a déjà une réponse ici:

  • Quelle est la différence entre la tâche et le fil? 8 réponses

je suis nouveau dans la programmation parallèle. Il y a deux classes disponibles dans .NET: Task et Thread .

donc, la question Est: Quelle est la différence entre ces cours? Quand est-il préférable d'utiliser Thread et quand Task ?

248
demandé sur Yves M. 2012-11-17 12:58:37

4 réponses

Thread est un concept de niveau inférieur: si vous démarrez directement un thread, vous savoir ce sera un thread séparé, plutôt que d'exécuter sur le pool de thread, etc.

Task est plus que juste une abstraction de "où d'exécuter du code" que - c'est vraiment juste "la promesse d'un résultat en l'avenir". Ainsi que quelques exemples différents:

  • Task.Delay n'a pas besoin de temps CPU réel; c'est tout comme la mise en place d'un minuteur pour aller dans le futur
  • une tâche retournée par WebClient.DownloadStringTaskAsync ne prendra pas beaucoup de temps CPU localement; elle représente un résultat qui est susceptible de passer la plupart de son temps dans la latence réseau ou le travail à distance (au serveur web)
  • une tâche retournée par Task.Run() vraiment est disant" Je veux que vous exécutiez ce code séparément"; le thread exact sur lequel ce code s'exécute dépend d'un certain nombre de facteurs.

notez que l'abstraction Task<T> est essentielle au support async dans C# 5.

en général, je vous recommande d'utiliser l'abstraction de niveau supérieur partout où vous le pouvez: dans le code C moderne, vous devriez rarement avoir besoin de lancer explicitement votre propre thread.

346
répondu Jon Skeet 2012-11-17 09:03:57

Source

Thread

Thread représente un thread réel au niveau de L'OS, avec sa propre pile et ses propres ressources du noyau. (techniquement, une implémentation CLR pourrait utiliser des fibres à la place, mais aucun CLR existant ne le fait) le Thread permet le plus haut degré de contrôle; vous pouvez annuler () ou suspendre() ou reprendre() un thread (bien que ce soit une très mauvaise idée), vous pouvez observer son état, et vous pouvez définir le niveau du thread propriétés comme la taille de la pile, l'état de l'appartement, ou la culture.

le problème avec le fil est que les fils OS sont coûteux. Chaque thread que vous avez consomme une quantité non-triviale de mémoire pour sa pile, et ajoute CPU supplémentaire au-dessus comme le contexte du processeur-commutateur entre les threads. Au lieu de cela, il est préférable d'avoir un petit pool de threads pour exécuter votre code comme le travail devient disponible.

il y a des moments où il n'y a pas D'alternative. Si vous avez besoin de spécifiez le nom (à des fins de débogage) ou l'état de l'appartement (pour afficher une interface utilisateur), vous devez créer votre propre Thread (notez que d'avoir plusieurs threads D'interface utilisateur est généralement une mauvaise idée). En outre, si vous voulez maintenir un objet qui est possédé par un seul thread et qui ne peut être utilisé que par ce thread, il est beaucoup plus facile de créer explicitement une instance Thread pour lui, de sorte que vous pouvez facilement vérifier si le code essayant de l'utiliser tourne sur le thread correct.

pool de threads

ThreadPool est un enveloppement autour d'un pool de threads maintenu par le CLR. ThreadPool ne vous donne aucun contrôle du tout; vous pouvez soumettre du travail à exécuter à un moment donné, et vous pouvez contrôler la taille de la piscine, mais vous ne pouvez rien définir d'autre. Vous ne pouvez même pas dire quand la piscine commencera à exécuter le travail que vous lui soumettez.

L'utilisation de ThreadPool évite de créer trop de threads. Cependant, si vous soumettez trop de tâches de longue durée pour le threadpool, il peut devenir plein, et plus tard le travail que vous soumettez peut finir par attendre les éléments plus anciens à terminer. De plus, le ThreadPool n'offre aucun moyen de savoir quand un travail a été terminé (contrairement au Thread).Join()), ni un moyen d'obtenir le résultat. Par conséquent, ThreadPool est mieux utilisé pour les opérations courtes où l'appelant n'a pas besoin du résultat.

tâche

enfin, la classe de tâche de la Bibliothèque parallèle offre le meilleur des deux mondes. Comme le ThreadPool, une tâche ne crée pas son propre fil OS. Au lieu de cela, les tâches sont exécutées par un TaskScheduler; l'ordonnanceur par défaut tourne simplement sur le ThreadPool.

contrairement au ThreadPool, la tâche vous permet également de savoir quand elle se termine, et (via la tâche générique) de retourner un résultat. Vous pouvez appeler ContinueWith () sur une tâche existante pour la faire exécuter plus de code une fois la tâche terminée (si elle est déjà terminée, elle s'exécutera le rappel immédiatement). Si la tâche est générique, ContinueWith () vous passera le résultat de la tâche, vous permettant d'exécuter plus de code qui l'utilise.

vous pouvez également attendre de façon synchrone qu'une tâche se termine en appelant Wait() (ou, pour une tâche générique, en obtenant la propriété résultat). Comme Thread.Join (), cela bloquera le thread appelant jusqu'à la fin de la tâche. Attendre une tâche de façon synchrone est généralement une mauvaise idée; cela empêche le thread appelant de faire tout autre travail, et peut conduisez aussi à des blocages si la tâche finit par attendre (même asynchrone) le fil courant.

étant donné que les tâches fonctionnent encore sur le ThreadPool, elles ne doivent pas être utilisées pour des opérations de longue durée, car elles peuvent encore remplir le pool de threads et bloquer de nouveaux travaux. Au lieu de cela, Task fournit une option LongRunning, qui dira au TaskScheduler de lancer un nouveau thread plutôt que de tourner sur le ThreadPool.

tous les nouveaux API de concurrence de haut niveau, y compris le Parallèle.Pour les méthodes* (), PLINQ, C# 5 attendent, et les méthodes async modernes dans la BCL, sont tous construits sur la tâche.

Conclusion

le résultat est que la tâche est presque toujours la meilleure option; elle fournit une API beaucoup plus puissante et évite de gaspiller les threads OS.

les seules raisons pour créer explicitement vos propres Threads dans le code moderne sont de définir des options par thread, ou de maintenir un fil qui a besoin de maintenir sa propre identité.

210
répondu M_ Fa 2015-07-13 11:22:46

tâche est un concept de niveau plus élevé que le thread ... et c'est ce que cette phrase signifie:

  1. Vous ne pouvez pas utiliser Abort/ThreadAbortedException, vous devez le soutenir annulez l'événement dans votre drapeau "code d'entreprise" qui teste périodiquement token.IsCancellationRequested (évitez également les connexions longues ou sans temps, par exemple vers db, sinon vous n'aurez jamais la chance de tester ce drapeau). Par la même raison Thread.Sleep(delay) doit être remplacé par Task.Delay(delay, token);

  2. il n'y a pas de fonctionnalité de méthodes de suspension() et de reprise() de thread avec des tâches. Exemple de tâche ne peut pas être réutilisée.

  3. mais vous obtenez deux nouveaux outils: continuations , et tâches imbriquées/enfants ; ces deux exemples démontrent l'idée et la syntaxe:

      // continuation - execute the delegate, when all tasks[] had been finished
    Task.Factory.ContinueWhenAll(
    tasks,
    () =>
       {
           int answer = tasks[0].Result + tasks[1].Result;
           Console.WriteLine("The answer is {0}", answer);
       }
    );
    
    
    //StartNew - starts task immediately, parent ends whith child
    var parent = Task.Factory.StartNew
    (() => {
              var child = Task.Factory.StartNew(() =>
             {
             //...
             });
          },  
          TaskCreationOptions.AttachedToParent
    );
    
  4. ainsi le thread système est complètement caché de la tâche, mais le code de la tâche est quand même exécuté dans le thread système concret. Les threads système sont des ressources pour les tâches et bien sûr il y a encore le pool de threads sous le capot de l'exécution parallèle des tâches. Il peut y avoir différentes stratégies comment thread obtenir de nouvelles tâches à exécuter. Une autre ressource partagée TaskScheduler s'en soucie. Certains problèmes que TaskScheduler résout 1) préfèrent exécuter la tâche 2) préfèrent exécuter les tâches dans l'ordre où elles ont été commencées - alias PreferFairness 3) répartition plus efficace des tâches entre les fils inactifs en fonction de la "connaissance préalable de l'activité des tâches" - alias vol de travail . Important: en général "async" n'est pas la même chose que "parallèle". Jouer avec les options TaskScheduler vous pouvez configurer des tâches asynchrones être exécuté en un seul thread de façon synchrone.

  5. tâches are integrated with C# async/wait features aka Promise Model , E. g il requestButton.Clicked += async (o, e) => ProcessResponce(await client.RequestAsync(e.ResourceName)); l'exécution de client.RequestAsync ne bloquera pas le fil UI. Important: sous le capot Clicked l'appel de délégué est absolument régulier (tout le threading est fait par compilateur).

C'est suffisant pour faire un choix. Si vous avez besoin de soutien Annulez la fonctionnalité d'appel de L'API legacy qui tend à s'accrocher (par exemple, connexion sans temporisation sime) et pour ce cas prend en charge le Thread.Abort(), ou si vous créez des calculs d'arrière - plan multithread et que vous voulez optimiser la commutation entre les threads en utilisant Suspend/Resume, cela signifie gérer l'exécution parallèle manuellement-stay with Thread. Sinon, allez à des tâches en raison d'eux vous donnera manipulation facile sur des groupes d'entre eux et sont intégrés dans la langue.

27
répondu Roman Pokrovskij 2018-09-21 18:02:14

la classe Thread est utilisée pour créer et manipuler un thread sous Windows.

a Task représente une opération asynchrone et fait partie de la bibliothèque parallèle de tâches , un ensemble D'API pour exécuter des tâches asynchrones et en parallèle.

dans les jours anciens (c.-à-d. avant TPL) il était celui en utilisant le Thread la classe était l'une des méthodes standard pour exécuter le code en arrière-plan ou en parallèle (une meilleure alternative était souvent d'utiliser un ThreadPool ), toutefois, cela a été lourd et a eu plusieurs inconvénients, dont le moindre était la performance overhead de créer un nouveau fil pour effectuer une tâche en arrière-plan.

de nos jours utiliser des tâches et la TPL est une bien meilleure solution 90% du temps car il fournit des abstractions qui permet beaucoup plus l'utilisation efficace des ressources du système. J'imagine qu'il y a quelques scénarios où vous voulez un contrôle explicite sur le thread sur lequel vous exécutez votre code, cependant de manière générale si vous voulez exécuter quelque chose de manière asynchrone, votre premier port d'appel devrait être le TPL.

26
répondu Justin 2014-03-27 19:12:45