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 :

Performance: Instanciation de variables dans des boucle


Sujet :

C++

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juillet 2010
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Juillet 2010
    Messages : 1
    Points : 0
    Points
    0
    Par défaut Performance: Instanciation de variables dans des boucle
    Bonjour,

    Question 1:

    Y a t'il une différence, en termes de performance ou de vitesse d’exécution, entre ce code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    double a=0;
    for(i=0; i < nBufferFrames; i++){
        a=f(i);
    }
    et celui-ci que je trouve plus 'évident' :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    for(i=0; i < nBufferFrames; i++){
        double a=f(i);
    }
    ?

    Question 2:

    Même question,
    Y a t'il une différence, en termes de performance ou de vitesse d’exécution, entre ce code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    class MaClasse{
    public:
        double m_min, m_max;
     
        double maFonction(){
            return m_max-m_min;
        }
     
        // constructeur
        MaClasse(double min, double max): m_min(min), m_max(max){ }
    }
     
    MaClasse MaClasse_1(110,220);
    for(i=0; i < nBufferFrames; i++){
        double a=MaClasse_1.maFonction();
    }
    et celui-ci que je trouve plus 'évident' :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    class MaClasse{
    public:
        double min, m_max;
     
        double maFonction(min, max){
            return max-min;
        }
     
    }
     
    MaClasse MaClasse_1;
    for(i=0; i < nBufferFrames; i++){
        double a=MaClasse_1.maFonction(110,220);
    }
    ?

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,
    Citation Envoyé par LuvKitteh Voir le message
    Bonjour,

    Question 1:

    Y a t'il une différence, en termes de performance ou de vitesse d’exécution, entre ce code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    double a=0;
    for(i=0; i < nBufferFrames; i++){
        a=f(i);
    }
    et celui-ci que je trouve plus 'évident' :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    for(i=0; i < nBufferFrames; i++){
        double a=f(i);
    }
    ?
    A priori, non...

    Les types primitifs ne sont qu'un ensemble de bits raccrochés les uns aux autres auxquels on donne une valeur 1 (le courent passe) ou 0 (le courent ne passe pas).

    Cependant, il est toujours conseillé de limiter au maximum la portée des variables.

    A moins d'avoir besoin du résultat de la dernière exécution de f en dehors de la boucle, il serait donc préférable de déclarer a dans la boucle, afin que sa "durée de vie" y soit limitée
    Question 2:

    Même question,
    Y a t'il une différence, en termes de performance ou de vitesse d’exécution, entre ce code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    class MaClasse{
    public:
        double m_min, m_max;
     
        double maFonction(){
            return m_max-m_min;
        }
     
        // constructeur
        MaClasse(double min, double max): m_min(min), m_max(max){ }
    }
     
    MaClasse MaClasse_1(110,220);
    for(i=0; i < nBufferFrames; i++){
        double a=MaClasse_1.maFonction();
    }
    et celui-ci que je trouve plus 'évident' :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    class MaClasse{
    public:
        double min, m_max;
     
        double maFonction(min, max){
            return max-min;
        }
     
    }
     
    MaClasse MaClasse_1;
    for(i=0; i < nBufferFrames; i++){
        double a=MaClasse_1.maFonction(110,220);
    }
    Tu as oublié une troisième solution qui serait proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    class MaClasse{
    public:
        double min, m_max;
     
        double maFonction(){
            return max-min;
        }
     
    };
    int main(){
        for(i=0; i < nBufferFrames; i++){
         MaClasse MaClasse_1(110,220);
        double a=MaClasse_1.maFonction();
        }
    }
    /* OU OU OU */
    class MaClasse{
    public:
        double maFonction(
        double min, double max;){
            return max-min;
        }
     
    };
    int main(){
        for(i=0; i < nBufferFrames; i++){
         MaClasse MaClasse_1;
        double a=MaClasse_1.maFonction(110,220);
        }
    }

    On peut faire sensiblement la même réponse, mais il faut y ajouter un petit bémol.

    Typiquement, une classe (ou une structure d'ailleurs) est, avant tout, une structure de données qui travaillent ensemble (sont utilisées ensemble) afin de permettre à la classe (ou à la structure) de fournir les services que l'on attend de sa part.

    Ces structures de données doivent être construites (comprend: les données, s'il y en a, doivent être initialisées à une valeur cohérente et utilisable) et sont détruite (si l'on n'utilise pas l'allocation dynamique de la mémoire du moins) automatiquement lorsque l'on quitte la portée dans laquelle les variables sont déclarées.

    La construction d'une structure de donnée (ou sa destruction) peut demander énormément de ressources, tant en terme de temps qu'en terme de mémoire utilisée:

    Une des données membres pourrait, par exemple, nécessiter une allocation dynamique de la mémoire, ou la copie d'un grand nombre d'autres données.

    En déclarant MaClasse_1 à l'intérieur de la boucle (comme pour le code que j'ai rajouté ), il serait construit à chaque début de boucle et détruit à chaque fois que l'on arrivera à l'accolade fermante "}" de la boucle.

    Si la construction (ou la destruction) de la structure prend du temps, tu risque de voir une réelle différence de performances

    Enfin, il faut savoir garder en mémoire que le but des arguments d'une fonction (ou d'une fonction membre dans le cas présent) est de fournir "tout ce qu'il manque" à la dite fonction pour pouvoir travailler.

    la différence entre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class MaClass1{
        public:
            MaClass1(double min, double max):min(minx),max(max){}
            void foo(){return max-min;}
        private:
            double min;
            double max;
    };
    int main(){
       MaClass obj(3.1415, 2.05);
       double a = obj.foo();
    }
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class MaClass2{
        public:
            void bar(double max, double min){return max - min;}
    };
     
    int main(){
       MaClass2 obj;
       double a = obj.foo(3.1415, 2.05);
    }
    est donc subtile, mais mérite d'être mise en évidence.

    Dans le premier cas, les données utilisées font partie de l'objet lui-même, c'est à dire qu'elles peuvent sans doute être utilisées par d'autres fonctions membres pour leurs propres "besoins personnels".

    On pourrait imaginer de rajouter une (ou plusieurs) fonction(s) à MaClasse1 qui utiliseraient min, ou max, ou les deux ou qui les modifieraient, afin de fournir un service particulier.

    Dans le second cas, min et max sont calculés "par ailleurs" mais ne sont, globalement, pas nécessaire à MaClasse2 pour fournir "la plupart des services" que l'on est en droit d'attendre de sa part.

    les valeurs de min et de max peuvent alors être modifiées de manière totalement indépendantes de MaClasse2 et n'influent que sur le comportement des fonctions auxquelles ils sont transmis, sans influer d'aucune manière (enfin, à moins que la fonction ne modifie elle-meme certains membres de MaClasse2) sur le comportement des autres fonctions membres éventuelles qui ne prendraient pas ces valeurs en paramètre.

    Il n'y a pas "une bonne" et "une mauvaise" solution dans ce cas...

    Il y a "une solution adaptée à un besoin exprimé" et une qui l'est moins

    Le premières solution sera adaptée lorsque la gestion du minimum et du maximum intervient dans la responsabilité que l'on donne à MaClasse1, alors que la seconde solution sera adaptée lorsque la gestion du minimum et du maximum échoit à "autre chose" (quoi que ca puisse etre) que MaClasse2
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Il me semble que le second code permet des optimizations parcequ'il est alors facile de prouver que 'a' n'est pas utilise hors de la boucle et peut etre duplique dans le cas d'un aplatissement de la boucle (elle est transformee en assembleur en copier/colle au lieu d'une vrai boucle).

    Il me semble aussi que la premiere boucle va etre automatiquement reordonnee en la seconde boucle par les passes d'optimization de la plupart des compilateurs SAUF si 'a' est utilise hors de la boucle.

    Moralite: utilise toujours les variables le plus proche possible de leur utilisation, sauf quand tu peux pas (seconde ecriture plutot que premiere sauf si tu utilises 'a' hors de la boucle).

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Klaim Voir le message
    Il me semble que le second code permet des optimizations parcequ'il est alors facile de prouver que 'a' n'est pas utilise hors de la boucle et peut etre duplique dans le cas d'un aplatissement de la boucle (elle est transformee en assembleur en copier/colle au lieu d'une vrai boucle).

    Il me semble aussi que la premiere boucle va etre automatiquement reordonnee en la seconde boucle par les passes d'optimization de la plupart des compilateurs SAUF si 'a' est utilise hors de la boucle.

    Moralite: utilise toujours les variables le plus proche possible de leur utilisation, sauf quand tu peux pas (seconde ecriture plutot que premiere sauf si tu utilises 'a' hors de la boucle).
    Evidemment, si tu pars du principe que le code tel que présenté est complet...

    J'étais personnellement parti du principe qu'il manquait peut etre quelques lignes dans la boucle
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Déclarer une variable dans une boucle ne change pas les performances du programme (je parle dans un cas avec beaucoup de variables et une boucle très longue) ? J'aurais toujours pensé que si pourtant...

    Citation Envoyé par Klaim
    Il me semble que le second code permet des optimizations parcequ'il est alors facile de prouver que 'a' n'est pas utilise hors de la boucle et peut etre duplique dans le cas d'un aplatissement de la boucle (elle est transformee en assembleur en copier/colle au lieu d'une vrai boucle).
    Je trouve ça encore plus étonnant. Dans ma logique de programmeur, toute variable déclarée sera du temps utilisé par ton programme pour les créer. Du coup il me paraîtrait plus logique que ce code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int a;
    float x;
     
    for (a = 0; a < 100; ++a)
    {
      x = powf(a);
    }
    soit plus rapide que celui-ci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int a;
     
    for (a = 0; a < 100; ++a)
    {
      float x(powf(a));
    }
    Comment le compilateur fait ça du coup ?

  6. #6
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    il s'en fout, les variables n'existe plus dans l'assembleur, seulement des registres et des zones de sauvegarde.

    en gros, déclarer x en dehors ne fait qu'ajouter un load/save autour de la boucle si elle est simple, et plein d'autre si le registre n'arrive pas a etre sauvegarder. (cas ou les calculs requiert tous les registres et qu'on garde 200 variables)
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  7. #7
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Citation Envoyé par leternel Voir le message
    il s'en fout, les variables n'existe plus dans l'assembleur, seulement des registres et des zones de sauvegarde.

    en gros, déclarer x en dehors ne fait qu'ajouter un load/save autour de la boucle si elle est simple, et plein d'autre si le registre n'arrive pas a etre sauvegarder. (cas ou les calculs requiert tous les registres et qu'on garde 200 variables)
    Justement : si la variable est déclarée avant la boucle, le programme allouera une plus grande taille à la pile pour stocker les variables dès l'entrée dans la fonction. Alors que si elle est déclarée dans la boucle... Décidément il me manque un truc là !

    PS: pourquoi tout le monde a un -1 ?

  8. #8
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Citation Envoyé par imperio Voir le message
    Justement : si la variable est déclarée avant la boucle, le programme allouera une plus grande taille à la pile pour stocker les variables dès l'entrée dans la fonction. Alors que si elle est déclarée dans la boucle... Décidément il me manque un truc là !
    L'allocation de la stack se fait a l'entree de la fonction, pas pendant.
    En fait les deux cas que tu presentes sont theoriquement equivalent. Voir:
    http://stackoverflow.com/questions/9...ithin-a-loop-c

    Mais l'optimization possible dont je parlais n'est pas directement lie. Disons que si tu utilses unev ariable vraiment que dans un context precis, le compilo peut deduire un tas de truc qui peut parfois permettre une optimization; si tu mets la variable dans un scope plus grand alors il peut faire moins.

    Ici je pensais essentiellemetn a l'aplatissement de la boucle qui dois etre plus facile a permettre si il y a une garantie que toutes les variables utilisees dans la boucle ne sont pas partagees entre les boucles. Si les variables sont declarees hors de la boucle, alors c'est difficile ou impossible a determiner, donc on ne tentera pas le type d'optimization liee.

    Il y a une explication peut etre plus clair la: http://stackoverflow.com/questions/7...ctice-2-parter


    PS: pourquoi tout le monde a un -1 ?
    Certainement quelqu'un qui comprends rien a ce qu'on dis ou un bot ou un truc dans le genre, fais pas attention.

  9. #9
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Merci pour les liens et les explications !

  10. #10
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par imperio Voir le message
    Justement : si la variable est déclarée avant la boucle, le programme allouera une plus grande taille à la pile pour stocker les variables dès l'entrée dans la fonction. Alors que si elle est déclarée dans la boucle... Décidément il me manque un truc là !
    Une variable d'un type de base (char, int etc) n'a aucune initialisation.
    Sa déclaration ne fait rien d'autre que... la déclarer, donc la redéclarer à chaque fois ne coute rien du tout.
    C'est pour les objets complexes avec appel à un constructeur que ça peut devenir lent et lourd
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  11. #11
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Une variable d'un type de base (char, int etc) n'a aucune initialisation.
    Sa déclaration ne fait rien d'autre que... la déclarer, donc la redéclarer à chaque fois ne coute rien du tout.
    C'est pour les objets complexes avec appel à un constructeur que ça peut devenir lent et lourd
    Pour des classes faisant des operations (allocation dynamique ou autre...) ca me paraissait evident mais je pensais qu'il en allait de meme avec les variables. Je me coucherai moins bete ce soir.

Discussions similaires

  1. Réponses: 3
    Dernier message: 17/04/2014, 10h26
  2. Réponses: 6
    Dernier message: 10/01/2013, 11h07
  3. Creer des variables dans un boucle for
    Par zentro dans le forum Général Python
    Réponses: 2
    Dernier message: 06/04/2008, 07h22
  4. Réponses: 2
    Dernier message: 11/07/2007, 10h40
  5. Afectation des variables dans une boucle
    Par Yoni Lebene dans le forum Delphi
    Réponses: 3
    Dernier message: 05/01/2007, 18h52

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