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++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  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
    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
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    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
    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
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    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 Expert
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    872
    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 : 872
    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

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    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 202
    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)

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