Freigeben über


GQ08 IX: petite optimisation Linq to object

Allez, une rapide pour la fin de journée.
Le truc est simple mais il est important de toujours l'avoir en tête lorsque l'on fait du Linq.

La requête suivante est correcte mais peut-être optimisée. Comment ?

 if (query.Count() == 0)
{
    //...
}

Dans le même genre:

 if ((from c in customers
     where c.City == "Paris"
     select c).Count() != 0)
{
}

Comments

  • Anonymous
    August 27, 2008
    PingBack from http://hubsfunnywallpaper.cn/?p=2561

  • Anonymous
    August 27, 2008
    en utilisant Any à la place de Count() != 0 : if ((from c in customers     where c.City == "Paris"     select c).Any()) En effet, le Any va ârrêter l'itération dès qu'il va en trouver un alors que le Count va passer tous les éléments.

  • Anonymous
    August 27, 2008
    On peut remplacer le count qui itère par un test sur First : if (q.First()==null) ... est équivalent à Count==0 la même chose peut s'appliquer à la seconde requête ou bien c'est un piège ? :-)

  • Anonymous
    August 27, 2008
    On peut remplacer le count qui itère par un test sur First : if (q.First()==null) ... est équivalent à Count==0 la même chose peut s'appliquer à la seconde requête ou bien c'est un piège ? :-)

  • Anonymous
    August 27, 2008
    Olivier, je ne suis pas d'accord. Au minimum, il faut utiliser FirstOrDefault(). First retournera une exception s'il n'y a aucun élément.

  • Anonymous
    August 27, 2008
    Matthieu ton observation est à la fois juste et fausse :-) Juste car si la liste est faite d'objets dont la valeur par défaut est "null" utiliser FirstOrDefault est plus élégant que d'utiliser First comme je le montrais, ce qui aurait obligé dans un code réellement fonctionnel à tester l'exception (ce que j'ai zappé car là n'était pas vraiment la question du quizz à mon sens). Mais ta remarque est fausse car si les objets de la liste ont vraiment une valeur par défaut (différente de "null") alors le test retourne le contraire de ce qui est attendu, ce qui est pour le moins facheux ! Exemple : List<int> liste = new List<int>(0); Console.WriteLine((q.Count()==0)); Console.WriteLine(q.FirstOrDefault()==null); hélas, si la première ligne retourne bien True, la seconde retourne False ! Les int ont pour valeur par défaut "0" et non null. De ce fait, ton objection ne m'apparaît pas fondée, car le test sur l'exception mis à part (et ajouté dans un code réel) l'utilisation de First est "générique" et produit toujours le résultat escompté alors que ta version réclamera de modifier le test en fonction de la valeur par défaut du type considéré, ce qui peut être la porte ouverte à un bug sournois découvert tardivement, le jour où on passe au code une liste d'éléments dont la valeur par défaut n'est pas "null"... Certes on pinaille un peu, mais vu que nous ne sommes que deux sur ce quizz, on a la place pour discuter et ça ne devrait gêner personne :-)

  • Anonymous
    August 27, 2008
    J'ai déjà rencontré le probleme sur le count() (encore pire j'avais fait un count(*)>0 la requete remontait tous les champs alors que le count() suffisait), effectivement niveau perf c'est à proscrire, vive le any(). trés bonne remarque qui sauvera la vie de bien des applications.

  • Anonymous
    August 27, 2008
    The comment has been removed

  • Anonymous
    August 28, 2008
    @ Matthieu. Le côté "coûteux" de la gestion des exceptions est un débat qui existe depuis Java et Delphi. Il y a en effet le clan de ceux qui disent comme toi "hou lala ! les exceptions c'est super lents donc il ne faut jamais s'en servir" et le clan opposé des fanatiques qui pensent l'inverse. Personnellement je préfère la position plus centrale: Dans la réalité je n'ai jamais vu une application (java, delphi ou C#) "ramer" à cause d'une gestion d'exception, c'est un mythe à mon sens du même ordre que celui qui veut que sous .NET il faut systématiquement utiliser un StringBuilder pour faire une concaténation de chaînes. Pour ce dernier cas j'ai d'ailleurs fait de nombreux tests et dans la majorité de ceux-ci, et contre la "pensée unique" de l'instant, une concaténation est plus rapide qu'un StringBuilder... Il en va de même des exceptions et je n'agréé donc pas ta position qui consiste en quelque sorte à les diaboliser. Sauf dans de très rares cas se priver des exceptions ne se justifie donc pas vraiment. Ici, sauf à montrer que le count est appelé dans une boucle de plusieurs milliers d'itérations, je pense que gérer une exception n'a strictement aucun impact sur les performances de l'application considérée. Mais bon, l'utilisation de Any n'est pas une mauvaise idée non plus, c'est une autre façon de tester s'il existe un élément comme First. Mais on pinaille encore :-) Quoi que le sujet soit très intéressant.

  • Anonymous
    August 28, 2008
    Ma réponse ici: http://blogs.msdn.com/mitsufu/archive/2008/08/28/r-ponse-gq08-ix-petite-optimisation-linq-to-object.aspx

  • Anonymous
    August 29, 2008
    L'association des mots "Mythe" et de "StringBuilder" dans une phrase de mon intervention plus haut ici m'a valu quelques remarques de lecteurs, afin de préciser le fond de ma pensée sur une question essentielle : la qualité d'un logiciel, je renvoie ceux que la question intéressent à ce billet que je viens d'écrire : http://www.e-naxos.com/Blog/post.aspx?id=166b0ef8-9323-47a3-ae49-26ed39deafac bonne lecture ! :-)