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

Contribuez Java Discussion :

[Perfs] Boucle for et iterateurs


Sujet :

Contribuez Java

  1. #1
    Expert éminent sénior Avatar de Uther
    Homme Profil pro
    Tourneur Fraiseur
    Inscrit en
    Avril 2002
    Messages
    4 552
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Tourneur Fraiseur

    Informations forums :
    Inscription : Avril 2002
    Messages : 4 552
    Points : 15 463
    Points
    15 463
    Par défaut [Perfs] Boucle for et iterateurs
    Tu as un lien? ca m'interesse.
    J'ai du mal a comprendre comment il peut y avoir une perte de performance significative entre le foreach et les for avec iterator, vu qu'il sont sencé fonctionner de la même manière.


    [edit par adiGuba] messages déplacées depuis la discussion suivante : http://www.developpez.net/forums/sho...d.php?t=460139

  2. #2
    Rédacteur
    Avatar de bulbo
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Février 2004
    Messages
    1 259
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Février 2004
    Messages : 1 259
    Points : 1 937
    Points
    1 937
    Par défaut
    Citation Envoyé par Uther Voir le message
    Tu as un lien? ca m'interesse.
    J'ai du mal a comprendre comment il peut y avoir une perte de performance significative entre le foreach et les for avec iterator, vu qu'il sont sencé fonctionner de la même manière.
    Pfiou c'est pas tout jeune comme discussion, je vais voir si je retrouve ça..

    [Edit]
    J'ai retrouvé une discussion mais ce n'est pas celle dont je me souviens car les tests étaient fait par adiGuba et on avait les temps d'exec de chacune des versions. Surtout que dans celle ci, on a une vision différente..
    Faudrais refaire les tests mais j'ai la flemme la ..

    Le lien: http://www.developpez.net/forums/sho...d.php?t=167491
    [/Edit]

    Bulbo
    [Java] [NetBeans] [CVS]
    La FAQ Java
    Merci de ne pas me poser de questions techniques par MP.

  3. #3
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par bulbo Voir le message
    (adiGuba l'a fait les résultat sont édifiant)
    Heu... je ne me souviens pas de cela

    Je pense que le "foreach" propose les mêmes performances qu'un parcours avec Iterator...

    D'ailleurs je viens de vérifier avec un javap -c et les deux méthodes suivantes produisent strictement le même bytecode :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    	public void printAll(List<? extends Object> list) {
    		for (Iterator<? extends Object> iter = list.iterator(); iter.hasNext(); ) {
    			Object value = iter.next();
    			System.out.println(value);
    		}
    	}
     
    	public void printAllEx(List<? extends Object> list) {
    		for (Object value : list) {
    			System.out.println(value);
    		}
    	}

    a++

  4. #4
    Rédacteur
    Avatar de bulbo
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Février 2004
    Messages
    1 259
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Février 2004
    Messages : 1 259
    Points : 1 937
    Points
    1 937
    Par défaut
    Hé béh je me fais vieux .. mes souvenirs se mélangent .. bon ce qui reste vrai c'est que l'index est plus rapide que l'iterator (sauf si je suis définitivement sénile)

    Et la nouvelle boucle for sur un tableau ? Je suis quand même pas fou, je suis sur que j'avais vu un bench ou le nouveau for était minable.. par contre ce n'était pas sur ce forum ..

    Je fais un test et je poste ici histoire de dissiper le malentendu je ne voudrais pas enduire tout le monde d'erreur ...

    Bulbo
    [Java] [NetBeans] [CVS]
    La FAQ Java
    Merci de ne pas me poser de questions techniques par MP.

  5. #5
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par bulbo Voir le message
    Hé béh je me fais vieux .. mes souvenirs se mélangent .. bon ce qui reste vrai c'est que l'index est plus rapide que l'iterator (sauf si je suis définitivement sénile)
    Ca ca dépend de l'implémentation (c'est vrai pour une ArrayList mais pas pour une LinkedList) et l'Iterator permet toujours le meilleur compromis...

    Citation Envoyé par bulbo Voir le message
    Et la nouvelle boucle for sur un tableau ? Je suis quand même pas fou, je suis sur que j'avais vu un bench ou le nouveau for était minable.. par contre ce n'était pas sur ce forum ..
    Ca c'est fort probable par contre (et il est possible qu'on en ai parlé mais je n'en suis pas sûr non plus )

    a++

  6. #6
    Rédacteur
    Avatar de bulbo
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Février 2004
    Messages
    1 259
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Février 2004
    Messages : 1 259
    Points : 1 937
    Points
    1 937
    Par défaut
    En fait j'ai fait le test (mais mon PC ramait a cause d'un backup à la con qui se déclenche entre 18h et 19h) et il semblerait (à confirmer demain) que le nouveau for soit plus rapide sur un tableau qu'une boucle avec index .. sur une grosse boucle je suis à 33 ms en moyenne contre 22 en moyenne avec le nouveau for

    Seul bémol du nouveau for c'est que c'est un accès en lecture seule..

    Bulbo
    [Java] [NetBeans] [CVS]
    La FAQ Java
    Merci de ne pas me poser de questions techniques par MP.

  7. #7
    Expert éminent sénior Avatar de Uther
    Homme Profil pro
    Tourneur Fraiseur
    Inscrit en
    Avril 2002
    Messages
    4 552
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Tourneur Fraiseur

    Informations forums :
    Inscription : Avril 2002
    Messages : 4 552
    Points : 15 463
    Points
    15 463
    Par défaut
    J'ai adapté le benchmarck que tu as posté en lien n'était pas vraiment adapté pour comparer les différente utilisation du for je l'ai changé en :
    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
        public static void main(String[] args) {
            int sum;
            List<Integer> list = new ArrayList();
            for(Integer l = 0; l < 8888888; l++) { list.add(l); }
     
            sum=0;
            long sTime1 = System.currentTimeMillis();
            for (Integer l = 0; l < list.size(); l++) { sum+=list.get(l); }
            System.out.println("for with get(): " + (System.currentTimeMillis() - sTime1));
     
            sum=0;
            long sTime2 = System.currentTimeMillis();
            for (Iterator<Integer> iter = list.iterator(); iter.hasNext();) { sum+=iter.next(); }
            System.out.println("for iterator: " + (System.currentTimeMillis() - sTime2));
     
            sum=0;
            long sTime3 = System.currentTimeMillis();
            for (int i : list) { sum+=i; }
            System.out.println("foreach : " + (System.currentTimeMillis() - sTime3));
        }
    ArrayList (itéré 8888888 fois):
    for with get(): 500
    for iterator: 562
    foreach : 547

    Donc il semblerait que le foreach soit légérement plus performant que l'itérateur classique

    LinkedList(itéré 8888888 fois):
    for with get(): impossible
    for iterator: 485
    foreach : 500

    Apparement ici c'est le foreach qui est plus lent.
    L'utilisation directe du get est impossible dans un délai raisonable(ca m'étonnerait pas qu'il y en aie pour plusieurs années, vu que la durée augmente exponentiellement).

    LinkedList(itéré seulement 88888 fois):
    for with get(): 72875
    for iterator: 0
    foreach : 0

    S'il fallait la preuve de l'interet des itérateurs pour une liste chainée, la c'est clair.

  8. #8
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Juste une remarque sur le benchmark : la différence tourne autour de 16ms or il se trouve que c'est le "pas" moyen de currentTimeMillis() sur la plupart des plateforme. Bref : ce n'est pas une différence significative.

    Il faudrait arrver à une différence de 500ms au moins pour que ce soit significatif.

    a++

  9. #9
    Expert éminent sénior Avatar de Uther
    Homme Profil pro
    Tourneur Fraiseur
    Inscrit en
    Avril 2002
    Messages
    4 552
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Tourneur Fraiseur

    Informations forums :
    Inscription : Avril 2002
    Messages : 4 552
    Points : 15 463
    Points
    15 463
    Par défaut
    J'ai adapté le bench pour avoir des délais plus long. Comme je ne pouvait pas agrandir la liste sans faire exploser ma machine, je l'ai mis les boucles for a l'intérieur d'une autre boucle for qui va de 1 à 100.
    Et là, surprise! Les résultats sont inverses de ce que j'avais auparavant. Par contre je me rend compte, que entre deux éxecutions à la suite du même bench, j'ai de sacrés différences même si on garde toujours le même classement.

    ArrayList(1er):
    for with get(): 47922
    for iterator: 55328
    foreach : 56016

    ArrayList(2eme):
    for with get(): 51912
    for iterator: 54978
    foreach : 55881


    LiskedList(1er):
    for iterator: 54788
    foreach : 54727

    LiskedList(2eme):
    for iterator: 55116
    foreach : 52511


    Je ne sais pas vraiment quoi conclure de ça ci ce n'est que:
    • Mieux vaut pas se prendre la tête ent foreach et iterator, et utiliser la notation que l'on préfère.
    • Utiliser le get augmentera à très légerement les performances d'une arraylist et ruinera celles d'une linkedList

  10. #10
    Membre expérimenté
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Points : 1 419
    Points
    1 419
    Par défaut
    Ces tests sont à nouveau biaisés... Il y a des casts +/- explicites dans certains et pas dans d'autres. De plus, la taille de la liste est parfois connue, parfois pas. Bref, sans vouloir être exhaustif, j'ai un peu amélioré le test.

    Dans les résultats, ce qui me choque, c'est la différence de temps entre une taille récupérée auparavant et utilisée, ou un appel récurrent à size().

    Exécution du test:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Résultats                   : [min, max, moyenne]
    Itérations                  : 100
    for with get() (1 x size()) : [46, 63, 58]
    for with get() (n x size()) : [78, 94, 85]
    for iterator                : [109, 125, 119]
    foreach                     : [109, 187, 120]


    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    package test;
     
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Iterator;
    import java.util.List;
     
    public class Test {
    	public static final int SIZE = 3000000;
    	public static final int ITERATIONS = 100;
     
    	public static void main(String[] args) {
     
    		long[] times1 = new long[ITERATIONS],
    		       times2 = new long[ITERATIONS],
    		       times3 = new long[ITERATIONS],
    		       times4 = new long[ITERATIONS];
    		List<Integer> list = new ArrayList<Integer>(SIZE);
    		int sum;
    		long time1, time2, time3, time4;
    		for (Integer i = 0; i < SIZE; i++) { list.add(i); }
     
    		for (int iterations = 0; iterations < ITERATIONS; iterations++) {
    			sum = 0;
    			time1 = System.currentTimeMillis();
    			for (int i = 0, l = list.size(); i < l; i++) { sum += list.get(i); }
    			time1 = System.currentTimeMillis() - time1;
     
    			sum = 0;
    			time2 = System.currentTimeMillis();
    			for (int i = 0; i < list.size(); i++) { sum += list.get(i); }
    			time2 = System.currentTimeMillis() - time2;
     
    			sum = 0;
    			time3 = System.currentTimeMillis();
    			for (Iterator<Integer> iter = list.iterator(); iter.hasNext();) { sum += iter.next(); }
    			time3 = System.currentTimeMillis() - time3;
     
    			sum = 0;
    			time4 = System.currentTimeMillis();
    			for (Integer i : list) { sum += i; }
    			time4 = System.currentTimeMillis() - time4;
     
    			times1[iterations] = time1;
    			times2[iterations] = time2;
    			times3[iterations] = time3;
    			times4[iterations] = time4;
    		}
     
    		times1 = stats(times1);
    		times2 = stats(times2);
    		times3 = stats(times3);
    		times4 = stats(times4);
     
    		System.out.println("Résultats                   : [min, max, moyenne]");
    		System.out.println("Itérations                  : " + ITERATIONS);
    		System.out.println("for with get() (1 x size()) : " + Arrays.toString(times1));
    		System.out.println("for with get() (n x size()) : " + Arrays.toString(times2));
    		System.out.println("for iterator                : " + Arrays.toString(times3));
    		System.out.println("foreach                     : " + Arrays.toString(times4));
    	}
     
    	public static long[] stats(long[] values) {
    		long[] stats = new long[] { Long.MAX_VALUE, 0, 0 };
    		for (long val : values) {
    			if (val < stats[0])
    				stats[0] = val;
    			if (val > stats[1])
    				stats[1] = val;
    			stats[2] += val;
    		}
    		stats[2] /= values.length;
    		return stats;
    	}
    }

  11. #11
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Comme je l'ai dit une différence trop petite n'est pas suffisamment "utile" car non seulement cela dépend de la granularité de currentTimeMillis() mais également d'autres éléments pertubateurs qu'ils soient externe (autres processus, etc.) ou interne (garbage collector, compilation à la volé).


    Dans ton premier exemple le for standard était fortement pénalisé car tu utilisais un Integer et que cela génèrait une grand nombre d'objet temporaire à cause de l'autoboxing, ce qui génèrait un grand nombre de passage du GC...


    Note qu'avec la JVM de Sun tu peux utiliser les paramètres -XX:+PrintGC -XX:+PrintCompilation pour afficher les passages du GC et la compilation à la volée...


    Et pour tester en performance pure tu pourrais aussi utiliser la JVM server

    a++

    PS : Note également que rien ne t'oblige à utiliser des objets différents : tu pourrais très bien stocker plusieurs fois le même objet pour ne pas trop charger la mémoire

  12. #12
    Membre expert
    Avatar de natha
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    2 346
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Janvier 2006
    Messages : 2 346
    Points : 3 083
    Points
    3 083
    Par défaut
    La différence de perf reste quand même anecdotique pour la plupart des applications.
    L'utilisation de l'Iterator est plus propre (peu importe si on utilise le for classique ou le foreach). Il est préférable d'avoir quelque chose de simple à expliquer ("Utilise toujours un itérateur") que de passer du temps à expliquer différents cas d'utilisation ("utilise l'index en général mais ATTENTION, si on utilise LinkedList etc. il faut que tu utilises un Iterator") pour finalement, quelque chose de simple, lire tous les éléments d'une liste.

    Je rajouterais même qu'un bon programmeur devrait coder :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    List list = new LinkedList();
    et pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    LinkedList list = new LinkedList();
    afin de ne pas être dépendant de l'implémentation.

    Ce qui revient à dire que l'utilisation des index est dangereuse et peut provoquer de gros bugs de régression. Et perso j'ai des bugs bien plus compliqués sur lesquels j'aimerais passer mon temps plutôt que traquer des ralentissements difficilement identifiables dûs à "une préférence syntaxique".

    Donc à moins de tester RandomAccess à chaque itération de liste (ce qui est lourdingue), je continuerais d'enseigner l'utilisation de l'Iterator, et si la notation [i] venait à se généraliser (ce à quoi, je le répète, je ne crois pas), il ne me restera pas d'autre choix que de la CheckStyliser avec un beau warning !
    Comment ça ? La réponse à ton problème n'est ni dans la faq, ni dans les tutos, ni dans sources ??? Etonnant...
    De la bonne manière de poser une question (et de répondre).
    Je ne fais pas de service par MP. Merci (...de lire les règles...).
    Ma page dvp.com

  13. #13
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par natha Voir le message
    La différence de perf reste quand même anecdotique pour la plupart des applications.
    L'utilisation de l'Iterator est plus propre (peu importe si on utilise le for classique ou le foreach). Il est préférable d'avoir quelque chose de simple à expliquer ("Utilise toujours un itérateur") que de passer du temps à expliquer différents cas d'utilisation ("utilise l'index en général mais ATTENTION, si on utilise LinkedList etc. il faut que tu utilises un Iterator") pour finalement, quelque chose de simple, lire tous les éléments d'une liste.
    +1 Tout à fait d'accord !


    L'iterator est la meilleure solution dans 99.99% des cas (pour le parcours d'une collection bien entendu). Pour le 0.01% des cas restant on peut toujours utilisé des accès direct par la suite lorsque le problème est bien ciblé


    a++

  14. #14
    Membre éprouvé
    Inscrit en
    Avril 2006
    Messages
    853
    Détails du profil
    Informations forums :
    Inscription : Avril 2006
    Messages : 853
    Points : 929
    Points
    929
    Par défaut
    dans les test que dingoth a donné, le premier est quand même 2 fois et demi plus rapide qu'un for each... ce qui est quand même pas négligeable..

  15. #15
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par robert_trudel Voir le message
    dans les test que dingoth a donné, le premier est quand même 2 fois et demi plus rapide qu'un for each... ce qui est quand même pas négligeable..
    Cela dépend : 50ms pour parcourir 3 millions d'éléments c'est plutôt négligeable pour moi.

    L'objectif de l'Iterator est de proposer le meilleurs compromis, et c'est ce qui est fait.


    Bien sûr cela dépend des besoins de l'application, mais je pense qu'il est généralement incorrect de remplacer les foreach par des for(i++) sur des List...


    a++

Discussions similaires

  1. Boucle for dans un script cmd
    Par nicolas.ganache dans le forum Développement
    Réponses: 4
    Dernier message: 19/07/2004, 17h07
  2. Réponses: 3
    Dernier message: 06/07/2004, 11h21
  3. [Debutant] Batch et Boucle for
    Par ludovic.fernandez dans le forum Scripts/Batch
    Réponses: 8
    Dernier message: 06/05/2004, 20h21
  4. [Swing][boucles] for, do, if .....comment faire simple?
    Par chastel dans le forum AWT/Swing
    Réponses: 7
    Dernier message: 02/05/2004, 23h49
  5. [langage] boucle "for" modification du pas
    Par K-ZimiR dans le forum Langage
    Réponses: 4
    Dernier message: 29/04/2004, 12h54

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