370 votes

Quand dois-je utiliser Lazy<T>?</T>

J’ai trouvé cet article sur `` : paresse dans c# 4.0 – Lazy

Quelle est la meilleure pratique d’avoir les meilleures performances en utilisant des objets paresseux ? Quelqu'un peut-il m’indiquer une utilisation pratique dans une application réelle ? En d’autres termes, Quand devrais-je l’utiliser ?

278voto

James Michael Hare Points 19077

Vous utilisez généralement il lorsque vous souhaitez instancier quelque chose la première fois son effectivement utilisé. Cela retarde le coût de la création jusqu'à ce que la si/quand il est nécessaire au lieu de toujours payer le coût.

Habituellement, cela est préférable lorsque l’objet peut ou ne peut pas être utilisé et le coût de la construction, il est non trivial.

142voto

Matthew Points 6516

Vous devriez essayer d’éviter d’utiliser des Singletons, mais si vous jamais dois, `` rend la mise en œuvre facile des singletons paresseux, thread-safe :

106voto

Despertar Points 5365

Un grand monde réel exemple de cas où le chargement paresseux est pratique est avec ORM (la Relation d'Objet Mappeurs) tels que Entity Framework et NHibernate.

Disons que vous avez une entité Client qui a des propriétés pour le Nom, Numéro de téléphone, et des Commandes. Nom et Numéro de téléphone sont régulièrement des cordes, mais les Ordres est une propriété de navigation qui retourne une liste de chaque commande, le client jamais fait.

Souvent, vous pouvez aller à travers tous vos clients et d'obtenir leur nom et leur numéro de téléphone pour les appeler. C'est une façon très rapide et simple de la tâche, mais imaginez si à chaque fois que vous avez créé un client automatiquement, il est allé et a fait une jointure complexe pour le retour des milliers de commandes. Le pire, c'est que vous n'êtes même pas allez utiliser les commandes, c'est un gaspillage de ressources!

C'est l'endroit idéal pour le chargement paresseux parce que si l'Ordre de propriété est paresseux, il ne sera pas aller chercher de l'ensemble de la commande du client, à moins que vous en ayez besoin. Vous pouvez énumérer les objets de Client que leur Nom et leur Numéro de Téléphone alors que le bien est patiemment de couchage, prêt pour quand vous en avez besoin.

46voto

Ben Points 856

J'ai été vu à l'aide de Lazy<T> propriétés pour aider à améliorer les performances de mon propre code (et pour en savoir un peu plus sur le sujet). Je suis venu ici à la recherche de réponses sur le moment de l'utiliser, mais il semble que partout où je vais il y a des phrases comme:

Utiliser l'initialisation tardive de différer la création d'un grand ou d' de ressources de l'objet ou de l'exécution d'une utilisation intensive des ressources la tâche, en particulier lorsque la création ou l'exécution peut ne pas se produire au cours de la durée de vie du programme.

à partir de MSDN Lazy<T> Class

Je suis resté un peu perplexe, parce que je ne suis pas sûr de savoir où tracer la ligne. Par exemple, je considère que l'interpolation linéaire comme un assez rapide calcul, mais si je n'ai pas besoin de le faire alors peut paresseux initialisation m'aider à éviter de le faire et est-il utile?

En fin de compte j'ai décidé d'essayer mes propres test et j'ai pensé que je voudrais partager les résultats ici. Malheureusement, je ne suis pas vraiment un expert à faire ce genre de tests et je suis donc heureux de recevoir des commentaires qui suggèrent des améliorations.

Description

Pour mon cas, j'ai été particulièrement intéressé à voir si Paresseux Propriétés pourraient aider à améliorer une partie de mon code qui fait beaucoup d'interpolation (la plupart étant inutilisés) et j'ai donc créé un test qui a comparé 3 approches.

J'ai créé une classe de test avec 20 propriétés de test (appelons les t-propriétés) pour chaque approche.

  • GetInterp Classe: Pistes de l'interpolation linéaire à chaque fois qu'un t-propriété est obtenu.
  • InitInterp Classe: Initialise le t-propriétés par l'exécution de l'interpolation linéaire pour chacun dans le constructeur. L'obtenir à peu renvoie un double.
  • InitLazy Classe: Définit le t-propriétés comme des Paresseux propriétés, de sorte que l'interpolation linéaire est exécuté une seule fois lorsque la propriété est d'abord obtenu. Ultérieure obtient faut juste retour déjà calculé double.

Les résultats du test sont mesurés en ms et sont la moyenne de 50 instanciations ou 20 propriété obtient. Chaque test a ensuite été exécuté 5 fois.

Test 1 Résultats: l'Instanciation (moyenne de 50 instanciations)

Class      1        2        3        4        5        Avg       %
------------------------------------------------------------------------
GetInterp  0.005668 0.005722 0.006704 0.006652 0.005572 0.0060636 6.72
InitInterp 0.08481  0.084908 0.099328 0.098626 0.083774 0.0902892 100.00
InitLazy   0.058436 0.05891  0.068046 0.068108 0.060648 0.0628296 69.59

Test 2 Résultats: de la Première à Obtenir (moyenne de 20 propriété obtient)

Class      1        2        3        4        5        Avg       %
------------------------------------------------------------------------
GetInterp  0.263    0.268725 0.31373  0.263745 0.279675 0.277775 54.38
InitInterp 0.16316  0.161845 0.18675  0.163535 0.173625 0.169783 33.24
InitLazy   0.46932  0.55299  0.54726  0.47878  0.505635 0.510797 100.00

Test 3 Résultats: Seconde (moyenne de 20 propriété obtient)

Class      1        2        3        4        5        Avg       %
------------------------------------------------------------------------
GetInterp  0.08184  0.129325 0.112035 0.097575 0.098695 0.103894 85.30
InitInterp 0.102755 0.128865 0.111335 0.10137  0.106045 0.110074 90.37
InitLazy   0.19603  0.105715 0.107975 0.10034  0.098935 0.121799 100.00

Observations

GetInterp est le plus rapide pour instancier comme prévu car sa ne fais rien. InitLazy est plus rapide pour instancier qu' InitInterp ce qui suggère que les frais généraux dans la mise en place paresseux propriétés est plus rapide que mon interpolation linéaire calcul. Cependant, je suis un peu confus ici, car InitInterp doit faire 20 une interpolation linéaire (pour créer un t-propriétés) mais c'est seulement en prenant 0.09 ms pour instancier (test 1), par rapport à l' GetInterp qui prend de 0,28 ms de faire juste une interpolation linéaire la première fois (test 2), et de 0,1 ms pour faire la deuxième fois (test 3).

Il prend InitLazy presque 2 fois plus long que GetInterp pour obtenir une propriété la première fois, alors qu' InitInterp est le plus rapide, car il peuplée ses propriétés lors de l'instanciation. (Au moins, c'est ce qu'elle aurait fait, mais pourquoi était-il de l'instanciation d'un résultat beaucoup plus rapide qu'une simple interpolation linéaire? Quand est-il exactement à faire ces interpolations?)

Malheureusement, il semble qu'il y est certains de code automatique d'optimisation passe dans mes tests. Il doit prendre en GetInterp le même temps pour obtenir un bien la première fois c'est la deuxième fois, mais il montre que plus de 2x plus rapide. Il ressemble à cette optimisation est également affecter les autres classes, car ils sont tous environ la même quantité de temps pour l'épreuve 3. Toutefois, ces optimisations peuvent également prendre place dans mon propre code de production qui peut également être un facteur important.

Conclusions

Alors que certains résultats sont comme prévu, il y a aussi de très intéressants résultats inattendus probablement en raison de code d'optimisations. Même pour les classes qui regardent comme ils sont en train de faire beaucoup de travail dans le constructeur, l'instanciation résultats montrent qu'ils peuvent encore être très rapide à créer, par rapport à l'obtention d'un double de la propriété. Alors que les experts dans ce domaine peut être en mesure de commenter et d'enquêter plus à fond, mon sentiment personnel est que j'ai besoin de faire ce test à nouveau, mais sur mon code de production afin d'examiner quel genre d'optimisations peut-être y a trop. Toutefois, je m'attends à ce qu' InitInterp peut être le chemin à parcourir.

14voto

Vasea Points 2475

À partir de MSDN:

Utiliser une instance de Paresseux pour différer la création d'un grand ou de ressources de l'objet ou de l'exécution d'une tâche gourmande en ressources, en particulier lorsque la création ou l'exécution peut ne pas se produire pendant la durée de vie du programme.

En plus de James Michael Lièvre réponse, Paresseux offre "thread-safe" initialisation de la valeur. Jetez un oeil à cette msdn article décrivant les différents types de fil de sécurité

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X