61 votes

FAQ sur les performances de LINQ

Je suis en train d'essayer de se familiariser avec LINQ. La chose qui me dérange le plus, c'est que même si je comprends la syntaxe de mieux, je ne veux pas involontairement sacrifier la performance pour l'expressivité.

Sont-ils bien dépôts centralisés de l'information ou des livres d'Effectif LINQ' ? À défaut, ce qui est de votre propre préférence personnelle de haute performance LINQ technique ?

Je suis surtout préoccupé par LINQ to Objects, mais toutes les suggestions sur LINQ to SQL et LINQ to XML également les bienvenus bien sûr. Merci.

85voto

KeithS Points 36130

Linq, comme un construit-dans la technologie, a des performances des avantages et des inconvénients. Le code de l'extension des méthodes considérablement la performance de l'attention portée par les .NET de l'équipe et de sa capacité à fournir une évaluation différée signifie que le coût de réalisation de la plupart des manipulations sur un ensemble d'objets est répandu à travers le plus grand algorithme nécessitant les manipulés ensemble. Cependant, il ya certaines choses que vous devez savoir qui peut faire ou défaire votre code de la performance.

D'abord et avant tout, Linq n'est pas comme par magie enregistrer votre programme de la mémoire et de temps nécessaire pour effectuer une opération; simplement, il peut retarder ces opérations jusqu'à ce absolument nécessaire. OrderBy() effectue un tri rapide, qui prendra nlogn le temps la même façon que si vous aviez écrit votre propre QuickSorter ou de la Liste utilisée.Sort() au bon moment. Donc, toujours être conscient de ce que vous demandez Linq à faire à une série lors de l'écriture de requêtes; si une manipulation n'est pas nécessaire, envisager la restructuration de la requête ou de la méthode de la chaîne de l'éviter.

De même, certaines opérations (tri, de regroupement, agrégats) nécessite la connaissance de l'ensemble qu'ils s'y conforment. Le dernier élément dans une série qui pourrait être la première, l'opération doit renvoyer à partir de son itérateur. En plus de cela, parce que Linq opérations ne devraient pas modifier leur source énumérable, mais la plupart des algorithmes qu'ils utilisent (c'est à dire en place toutes sortes), ces opérations de fin non seulement à évaluer, mais la copie de l'ensemble énumérable en béton, finis de la structure, l'exécution de l'opération, et céder à travers elle. Donc, lorsque vous utilisez OrderBy() dans une déclaration, et vous demandez à un élément dans le résultat final, TOUT ce que l'interface IEnumerable donné qu'il peut produire est évaluée, stockées dans la mémoire comme un tableau, triés, puis est retourné un élément à la fois. La morale est, toute opération qui a besoin d'un ensemble fini au lieu d'une énumération doit être placé le plus en retard dans la requête que possible, en permettant à d'autres opérations comme l'endroit Où() et Sélectionnez() afin de réduire la cardinalité et la mémoire de l'empreinte de la source.

Enfin, les méthodes Linq augmenter considérablement la taille de la pile d'appel et de la mémoire de votre système. Chaque opération qui doit connaître de l'ensemble conserve toute source fixés dans la mémoire jusqu'à ce que le dernier élément a été réaffirmé, et l'évaluation de chaque élément impliquera une pile d'appel au moins deux fois plus profond que le nombre de méthodes dans votre chaîne ou des clauses de votre inline déclaration (un appel à chaque itérateur est MoveNext() ou rendement GetEnumerator, plus au moins un appel à chaque lambda le long du chemin). C'est tout simplement le résultat dans un plus grand, plus lent qu'un algorithme intelligemment conçu inline algorithme qui effectue les mêmes manipulations. Linq est le principal avantage est la simplicité du code. La création, puis le tri, un dictionnaire des listes de groupes de valeurs n'est pas très facile à comprendre le code (croyez-moi). Micro-optimisations peuvent obscurcir davantage. Si la performance est votre préoccupation principale, puis ne pas utiliser Linq; il va ajouter environ 10% de surcharge de temps et plusieurs fois la surcharge de la mémoire de la manipulation d'une liste sur place vous-même. Cependant, la facilité de maintenance est généralement la principale préoccupation des développeurs, et Linq aide vraiment là.

Sur le coup de pied de performance: Si les performances de votre algorithme est le sacré, uncompromisable première priorité, vous seriez de programmation dans un langage non managé comme C++; .NET va être beaucoup plus lent juste en vertu de celui-ci étant géré de l'environnement d'exécution, avec JIT compilation native, la mémoire gérée et extra threads du système. Je voudrais adopter une philosophie de l'être "assez bon"; Linq peut introduire des ralentissements, de par sa nature, mais si vous ne pouvez pas faire la différence, et votre client ne peut pas faire la différence, alors, à toutes fins pratiques, il n'y a pas de différence. "L'optimisation prématurée est la racine de tout mal"; le Faire fonctionner, PUIS chercher les occasions de le rendre plus performant, jusqu'à ce que vous et votre client d'accord que c'est assez bon. Il pourrait toujours être "mieux", mais si vous voulez être de la main-d'emballage code machine, vous trouverez un point de moins qu'au cours de laquelle vous pouvez déclarer la victoire et se déplacer.

58voto

Rex M Points 80372

Tout simplement la compréhension de ce que LINQ est en train de faire à l'interne devrait donner suffisamment d'informations pour savoir si vous prenez un gain de performance.

Voici un exemple simple où LINQ aide à la performance. Considérez ceci typique de la vieille école approche:

List<Foo> foos = GetSomeFoos();
List<Foo> filteredFoos = new List<Foo>();
foreach(Foo foo in foos)
{
    if(foo.SomeProperty == "somevalue")
    {
        filteredFoos.Add(foo);
    }
}
myRepeater.DataSource = filteredFoos;
myRepeater.DataBind();

Donc le code ci-dessus va se répéter deux fois et allouer un second récipient pour contenir les valeurs filtrées. Quel gaspillage! Comparer avec:

var foos = GetSomeFoos();
var filteredFoos = foos.Where(foo => foo.SomeProperty == "somevalue");
myRepeater.DataSource = filteredFoos;
myRepeater.DataBind();

Cela ne parcourt qu'une seule fois (lors de la répétition est liée); il n'a jamais utilise le contenant d'origine; filteredFoos est juste un intermédiaire énumérateur. Et si, pour une raison quelconque, vous décidez de ne pas lier le répéteur plus tard, rien n'est perdu. Vous n'avez même pas itération ou d'évaluer une fois.

Lorsque vous arrivez à la très complexe de la séquence de manipulations, vous pouvez potentiellement gagner beaucoup en misant sur LINQ inhérents à l'utilisation de chaînage et d'évaluation différée. Encore une fois, comme avec n'importe quoi, c'est juste une question de compréhension de ce qu'il est en train de faire.

10voto

ssg Points 20321

L'autre hic, c'est que pas toutes les méthodes LINQ peut être optimisé pour une classe donnée. Par exemple, SomeCollection.Count() peut-être: O(N) alors SomeCollection.Count serait O(1), parce que LINQ revient à IEnumerable mise en œuvre chaque fois que la classe n'est pas de fournir une alternative plus rapide.

De même, SomeLookup.HasKey(a) pourrait être beaucoup plus rapide que l' SomeLookup.Any(i => i.Key == a).

Autant que je sache commun .NET des contenants comme List et Dictionary ne souffrent pas de ces pénalités. Mais ce serait la meilleure pratique consiste à utiliser la classe' méthode native, si disponible.

4voto

David Burton Points 318

Il y a divers facteurs qui influent sur le rendement.

Souvent, le développement d'une solution à l'aide de LINQ offrira assez raisonnable de la performance parce que le système peut générer une expression de l'arbre pour représenter la requête sans l'exécution de la requête lors de la génération présente. Seulement lorsque vous parcourez les résultats n'utilise pas cette expression de l'arbre de générer et d'exécuter une requête.

En termes d'efficience absolue, la course contre prédéfinis procédures stockées, vous pouvez voir certaines de performances, mais en général, l'approche à adopter est de développer une solution en utilisant un système qui offre des performances acceptables (comme LINQ), et ne pas s'inquiéter à propos de quelques pour cent de la perte de performance. Si une requête est ensuite exécute lentement, alors peut-être vous regardez l'optimisation.

La réalité est que la majorité des requêtes n'aura pas le moindre problème avec le fait d'être fait via LINQ. Le fait est que si votre requête s'exécute lentement, il est probablement plus susceptibles d'avoir des problèmes avec l'indexation, de la structure, etc, que la requête elle-même, de sorte que même lorsque vous cherchez à optimiser les choses dont vous aurez souvent pas toucher le LINQ, juste la structure de base de données, c'est travailler contre.

Pour la manipulation de XML, si vous avez un document en cours de chargement et analysé dans la mémoire (comme quoi que ce soit basé sur le modèle DOM, ou un XmlDocument ou quoi que ce soit), alors vous aurez plus de l'utilisation de la mémoire que les systèmes qui ne sont quelque chose comme des collectes pour indiquer à trouver un début ou à la fin de la balise, mais non de la construction d'une mémoire version du document (comme SAX ou XmlReader). L'inconvénient est que la manifestation de traitement est généralement un peu plus complexe. Encore une fois, avec la plupart des documents, il ne sera pas un problème - la plupart des systèmes ont plusieurs GO de RAM, donc, en prenant un peu de MO représente un seul document XML n'est pas un problème (et souvent de traiter un grand ensemble de documents XML au moins un peu de manière séquentielle). C'est seulement si vous avez un énorme fichier XML qui prendrait 100 de MO que vous vous inquiétez au sujet de son choix.

Gardez à l'esprit que LINQ permet de parcourir en mémoire des listes et ainsi de suite ainsi, si dans certaines situations (comme l'endroit où vous allez utiliser un ensemble de résultats, encore et encore dans une fonction), vous pouvez utiliser .ToList ou .ToArray pour retourner les résultats. Parfois, cela peut être utile, bien que généralement vous voulez essayer d'utiliser la base de données de l'interrogation plutôt en mémoire.

Comme pour les favoris - NHibernate LINQ - c'est un objet-relationnel outil de cartographie qui vous permet de définir des classes, de définir la cartographie des détails, et puis l'obtenir pour générer la base de données de vos classes, plutôt que l'inverse, et la prise en charge LINQ est assez bonne (certainement mieux que les goûts de Subsonique).

1voto

theburningmonk Points 5590

Il y a un projet codeplex appelé i4o que j'ai utilisé un temps, qui peuvent aider à améliorer les performances de Linq to Objects dans le cas où vous êtes en train de faire de l'égalité des comparaisons, par exemple

from p in People 
where p.Age == 21 
select p;

http://i4o.codeplex.com/ Je n'ai pas testé avec .Net 4 ne peut donc pas affirmer qu'il fonctionne toujours, mais la peine de vérifier. Pour le faire fonctionner sa magie vous la plupart ont juste pour décorer votre classe avec certains attributs de spécifier la propriété qui doivent être indexés. Lorsque je l'ai utilisé avant qu'il ne fonctionne qu'avec l'égalité des comparaisons bien.

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