IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Linq et optmisation aggressive du code


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Par défaut Linq et optmisation aggressive du code
    Hello,

    Je suis recemment tombé sur un bout de code qui m'inquiète un peu :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class Foo {
       public bool Bar {get; set; }
    }
    List<Foo> foos = ...;
     
    foos.Select(a => a.Bar = true).ToList();
    C'est équivalent de foos.ForEach(a => a.Bar = true);, en moins lisible.

    Mais vu qu'on fait un Select sans récupérer le résultat, y a t'il un risque que le compilo vire l'instruction pour une histoire d'optimisation ?

    edit: puis j’imagine qu'une nouvelle List est créée même si non récupérée ?

  2. #2
    Membre chevronné Avatar de WaterTwelve21
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2015
    Messages
    270
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Décembre 2015
    Messages : 270
    Par défaut
    Bonjour ,

    La MSDN l'explique trés bien ( Voir section Notes ) https://msdn.microsoft.com/fr-fr/lib...v=vs.110).aspx .

    La personne aurai pu trés bien faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    List<Foo> foos = ....Select(a => a.Bar = true).ToList();
    Elle à décidé de passer en deux temps.

    Et je suis pas d'accord , en quoi c'est moins lisible qu'un forEach ?

  3. #3
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 941
    Par défaut
    Citation Envoyé par WaterTwelve21 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    List<Foo> foos = ....Select(a => a.Bar = true).ToList();
    Ce que produit cette ligne de code n'est pas une List<Foo> mais une List<bool> dont les éléments sont tous à true.

    Citation Envoyé par WaterTwelve21 Voir le message
    Et je suis pas d'accord , en quoi c'est moins lisible qu'un forEach ?
    Personnellement je trouve que ça crée une indirection de sens, puisqu'un Select() sert en premier lieu à faire une projection, qui masque l'intention de l'auteur, à savoir parcourir la liste d'objets pour les modifier.

  4. #4
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 941
    Par défaut
    Citation Envoyé par Iradrille Voir le message
    Mais vu qu'on fait un Select sans récupérer le résultat
    Le résultat du Select (à savoir un constructeur de requête, et non une liste) est bien récupéré, à travers le ToList() qui est une méthode de "closure". L'appel à ToList() ou ToArray() est même parfois utiliser pour forcer l'exécution des requêtes en profitant de l'effet de bord.

    Citation Envoyé par Iradrille Voir le message
    edit: puis j’imagine qu'une nouvelle List est créée même si non récupérée ?
    En théorie je dirais oui, en pratique je ne sais pas si le compilateur est suffisamment optimisé pour voir que cette liste n'est pas récupérée et éviter sa création même s'il effectue le parcours de l'ensemble source.

    Mais après je suis d'accord que si ce code est techniquement correct il est en revanche sémantiquement faux.

  5. #5
    Membre Expert
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Par défaut
    Citation Envoyé par WaterTwelve21 Voir le message
    Bonjour ,

    La MSDN l'explique trés bien ( Voir section Notes ) https://msdn.microsoft.com/fr-fr/lib...v=vs.110).aspx
    La doc ne précise pas si l'appel peut être supprimé par optimisation.

    Citation Envoyé par WaterTwelve21 Voir le message
    Et je suis pas d'accord , en quoi c'est moins lisible qu'un forEach ?
    Un Select c'est fait pour sélectionner (ie, foos devrait être une List constante d'objets constants).
    C'est comme faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class Foo {
       int Bar { get; set; }
       int Baz { get { Bar = 42; return 0; } // <- valide mais ... c'est pas le rôle d'un getter !
       // un getter n'est pas censé modifier l'objet (hors éventuel besoin de synchronisation ou système de cache, mais c'est particulier)
    }
    En appelant un getter tu t'attends à ce que l'objet ne soit pas modifié.
    De même pour un Select, tu t'attends à ce que la liste ne soit pas modifiée (ni les items quelle contient).

    Citation Envoyé par Noxen Voir le message
    Le résultat du Select (à savoir un constructeur de requête, et non une liste) est bien récupéré, à travers le ToList() qui est une méthode de "closure". L'appel à ToList() ou ToArray() est même parfois utiliser pour forcer l'exécution des requêtes en profitant de l'effet de bord.
    Aucun risque que le compilo se dise "la liste résultat n'est pas utilisée, je n'appelle donc pas ToList()" ? -> si ToList n'est pas appelée, le Select n'est pas exécuté.
    Ça me semble une optimisation valide et possible, mais vu l'absence de paramètres constants je sais pas comment ça se passe en C#.

  6. #6
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 941
    Par défaut
    Il ne parait pas légitime de laisser le compilateur ignorer un appel explicite de méthode, même un simple get, qui renvoie une valeur mais ne l'utilise pas, au prétexte d'optimisations. Ce n'est pas parce-qu'une méthode renvoie une valeur qu'elle n'a pas d'autres effets attendus, qui ne se produiraient pas dans ce cas là. De plus la méthode ToList() est expressément présentée dans la msdn (Enumerable.ToList<T>()) comme une technique légitime pour obtenir une évaluation immédiate de la requête. Si optimisation il y avait, et dans la mesure où ces méthodes d'extension sont sous la maîtrise de Microsoft, ce serait de ne pas créer la structure qui emporte la valeur de retour si celle-ci n'est pas utilisée.

    À l'inverse, une méthode comme Select() est présentée explicitement comme retournant une objet constructeur qui effectue une évaluation différée de la requête.

  7. #7
    Membre chevronné Avatar de WaterTwelve21
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2015
    Messages
    270
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Décembre 2015
    Messages : 270
    Par défaut
    Vous m'avez convaincu pour la comparaison au ForEach , le Select se la joue double jeu (selection , transformation) .

    D'ailleurs à l'utilisation dans l'IDE , je cite visual studio :

    Projects each element of a sequence in a new collection
    selector : A transform function to apply to each element
    De ce que j'ai compris , c'est ce que Noxem explique dans sa derniere déclaration.

    une méthode comme Select() est présentée explicitement comme retournant une objet constructeur qui effectue une évaluation différée de la requête.

  8. #8
    Expert confirmé

    Homme Profil pro
    Responsable déploiement (SCCM, InTune, GPO)
    Inscrit en
    Juillet 2014
    Messages
    3 218
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Responsable déploiement (SCCM, InTune, GPO)
    Secteur : Transports

    Informations forums :
    Inscription : Juillet 2014
    Messages : 3 218
    Par défaut
    Pour ma part je me demande pourquoi utiliser le select sachant que le foreach existe. Je le trouve plus naturel à lire et ce type d'utilisation de select peux amener des dérives.

    L'utilisation du select doit occasionner une consommation de mémoire supplémentaire puisqu'il doit prévoir de retourner la liste projeté contrairement au foreach qui ne retourne rien et qui ne fait que modifier les éléments existants.

    Côté performance, en vitesse d'exécution, le foreach est plus de 3 fois plus rapide sur mon poste (300ms vs 1050ms).

    Donc je ne vois pas pourquoi utiliser le select dans ce cas précis puisqu'il est :
    -Plus lent
    -Plus consommateur de mémoire
    -Plus long à écrire (ligne de code)
    -Moins lisible, intuitif

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 19/11/2015, 15h55
  2. Réponses: 2
    Dernier message: 28/09/2011, 17h27
  3. De la rapidité du code
    Par jfloviou dans le forum Contribuez
    Réponses: 233
    Dernier message: 29/05/2009, 02h17
  4. [LINQ] Datagridview Ajouter ligne par code ?
    Par matrix3 dans le forum Framework .NET
    Réponses: 2
    Dernier message: 02/06/2008, 09h42
  5. OmniORB : code sous Windows et Linux
    Par debug dans le forum CORBA
    Réponses: 2
    Dernier message: 30/04/2002, 17h45

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo