web-dev-qa-db-fra.com

Est-il considéré acceptable de ne pas appeler Dispose () sur un objet TPL Task?

Je veux déclencher une tâche à exécuter sur un thread d'arrière-plan. Je ne veux pas attendre la fin des tâches.

Dans .net 3.5 j'aurais fait ceci:

ThreadPool.QueueUserWorkItem(d => { DoSomething(); });

Dans .net 4, le TPL est la méthode suggérée. Le modèle commun que j'ai vu recommandé est:

Task.Factory.StartNew(() => { DoSomething(); });

Cependant, la méthode StartNew() renvoie un objet Task qui implémente IDisposable. Cela semble être ignoré par les personnes qui recommandent ce modèle. La documentation MSDN sur la méthode Task.Dispose() dit:

"Appelez toujours Dispose avant de libérer votre dernière référence à la tâche."

Vous ne pouvez pas appeler disposer sur une tâche jusqu'à ce qu'elle soit terminée, donc avoir le thread principal en attente et appeler disposer défait le point de faire sur un thread d'arrière-plan en premier lieu. Il ne semble pas non plus y avoir d'événement terminé/terminé pouvant être utilisé pour le nettoyage.

La page MSDN de la classe Task ne fait aucun commentaire à ce sujet et le livre "Pro C # 2010 ..." recommande le même modèle et ne fait aucun commentaire sur l'élimination des tâches.

Je sais que si je le laisse, le finaliseur le rattrapera à la fin, mais est-ce que ça va revenir et me mordre quand je fais beaucoup de feu et oublier des tâches comme ça et le fil du finaliseur est débordé?

Mes questions sont donc:

  • Est-il acceptable de ne pas appeler Dispose() sur la classe Task dans ce cas? Et si oui, pourquoi et y a-t-il des risques/conséquences?
  • Y a-t-il une documentation qui en discute?
  • Ou existe-t-il un moyen approprié de supprimer l'objet Task que j'ai manqué?
  • Ou existe-t-il une autre façon de faire du feu et d'oublier des tâches avec le TPL?
116
Simon P Stevens

Il y a une discussion à ce sujet dans les forums MSDN .

Stephen Toub, membre de l'équipe Microsoft pfx a ceci à dire:

Task.Dispose existe parce que Task peut potentiellement encapsuler un descripteur d'événement utilisé lors de l'attente de la tâche, dans le cas où le thread en attente doit réellement se bloquer (par opposition à la rotation ou potentiellement à l'exécution de la tâche en attente). Si tout ce que vous faites est d'utiliser des continuations, ce descripteur d'événement ne sera jamais alloué
...
il vaut probablement mieux compter sur la finalisation pour s'occuper des choses.

Mise à jour (octobre 2012)
Stephen Toub a publié un blog intitulé Dois-je disposer des tâches? qui donne plus de détails et explique les améliorations de .Net 4.5.

En résumé: vous n'avez pas besoin de disposer des objets Task 99% du temps.

Il y a deux raisons principales pour éliminer un objet: libérer des ressources non gérées de manière déterministe et en temps opportun, et éviter les coûts d'exécution du finaliseur de l'objet. Aucun de ces éléments ne s'applique à Task la plupart du temps:

  1. Depuis .Net 4.5, la seule fois où un Task alloue le handle d'attente interne (la seule ressource non gérée dans l'objet Task) est lorsque vous utilisez explicitement le IAsyncResult.AsyncWaitHandle du Task, et
  2. L'objet Task lui-même n'a pas de finaliseur; le handle est lui-même enveloppé dans un objet avec un finaliseur, donc à moins qu'il ne soit alloué, il n'y a pas de finaliseur à exécuter.
100
Kirill Muzykov

Il s'agit du même type de problème qu'avec la classe Thread. Il consomme 5 descripteurs de système d'exploitation mais n'implémente pas IDisposable. Bonne décision des concepteurs d'origine, il existe bien sûr peu de façons raisonnables d'appeler la méthode Dispose (). Vous devez d'abord appeler Join ().

La classe Task ajoute une poignée à cela, un événement de réinitialisation manuelle interne. Quelle est la ressource de système d'exploitation la moins chère qui soit? Bien sûr, sa méthode Dispose () ne peut libérer que l'un des descripteurs d'événement, pas les 5 descripteurs consommés par Thread. Ouais, ne vous embêtez pas .

Attention, vous devez être intéressé par la propriété IsFaulted de la tâche. C'est un sujet assez laid, vous pouvez en savoir plus à ce sujet dans cet article de la bibliothèque MSDN . Une fois que vous avez traité cela correctement, vous devriez également avoir une bonne place dans votre code pour disposer des tâches.

14
Hans Passant