Le moyen le plus rapide d'itérer un tableau en Java: variable de boucle vs amélioré pour l'instruction [dupliquer]

StackOverflow https://stackoverflow.com/questions/1006395

  •  06-07-2019
  •  | 
  •  

Question

    

Cette question a déjà une réponse ici:

         

En Java, est-il plus rapide de parcourir un tableau à l'ancienne,

for (int i = 0; i < a.length; i++)
    f(a[i]);

Ou en utilisant la forme plus concise,

for (Foo foo : a)
    f(foo);

Pour une liste de tableaux, la réponse est-elle la même?

Bien sûr, pour la grande majorité du code d’application, la réponse est qu’elle ne fait aucune différence perceptible. Par conséquent, la forme la plus concise doit être utilisée pour la lisibilité. Cependant, le contexte que je considère est celui du calcul technique intensif, avec des opérations qui doivent être effectuées des milliards de fois, de sorte que même une petite différence de vitesse pourrait devenir importante.

Était-ce utile?

La solution

Si vous parcourez un tableau, cela ne devrait pas avoir d'importance - la boucle for améliorée utilise quand même des accès au tableau.

Par exemple, considérons ce code:

public static void main(String[] args)
{
    for (String x : args)
    {
        System.out.println(x);
    }
}

Une fois décompilé avec javap -c Test , nous obtenons (pour la méthode main ):

public static void main(java.lang.String[]);
  Code:
   0:   aload_0
   1:   astore_1
   2:   aload_1
   3:   arraylength
   4:   istore_2
   5:   iconst_0
   6:   istore_3
   7:   iload_3
   8:   iload_2
   9:   if_icmpge   31
   12:  aload_1
   13:  iload_3
   14:  aaload
   15:  astore  4
   17:  getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   20:  aload   4
   22:  invokevirtual   #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   25:  iinc    3, 1
   28:  goto    7
   31:  return

Modifiez-le pour utiliser un accès explicite à un tableau:

public static void main(String[] args)
{
    for (int i = 0; i < args.length; i++)
    {
        System.out.println(args[i]);
    }
}

Ceci se décompile en:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   aload_0
   4:   arraylength
   5:   if_icmpge   23
   8:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  aload_0
   12:  iload_1
   13:  aaload
   14:  invokevirtual   #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   17:  iinc    1, 1
   20:  goto    2
   23:  return

Il y a un peu plus de code d'installation dans la boucle for améliorée, mais ils font essentiellement la même chose. Aucun itérateur n'est impliqué. De plus, je m'attendrais à ce qu'ils se sentent surpris à un code encore plus similaire.

Suggestion: si vous pensez réellement que cela peut faire une différence significative (ce que cela ne ferait que jamais si le corps de la boucle est absolument minuscule), vous devez le comparer à votre application réelle. C’est la seule situation qui compte.

Autres conseils

Cela tombe carrément dans le champ de la micro-optimisation . Cela n'a pas d'importance. Stylistiquement, je préfère toujours le second parce qu'il est plus concis, à moins que vous n'ayez besoin du compteur de boucles pour autre chose. Et c’est bien plus important que ce type de micro-optimisation : la lisibilité.

Cela étant dit, il n'y aura pas beaucoup de différence pour un ArrayList, mais un LinkedList sera beaucoup plus efficace avec le second.

Mesurez-le. La réponse à toutes les questions relatives aux performances peut dépendre de la version de la machine virtuelle, du processeur, de la vitesse de la mémoire, des caches, etc. Vous devez donc la mesurer pour votre plate-forme particulière.

Personnellement, je préférerais la deuxième variante, car l’intention est plus claire. Si les performances deviennent un problème, je peux quand même les optimiser ultérieurement - si ce code est vraiment important pour les performances de l'ensemble de l'application.

Pour une liste liée:

for(ClassOfElement element : listOfElements) {
  System.out.println(element.getValue());
}

Il a été répondu auparavant:

Est existe-t-il une différence de performance entre une boucle for et une boucle for each?

Sur un tableau ou une collection RandomAccess, vous pouvez obtenir une augmentation très rapide de la vitesse en procédant comme suit:

List<Object> list = new ArrayList<Object>();

for (int i=0, d=list.size(); i<d; i++) {
    something(list.get(i));
}

Mais je ne m'inquiéterais pas en général. Des optimisations comme celle-ci ne feront pas plus de 0,1% de différence pour votre code. Essayez d’appeler java avec -prof pour voir où votre code passe réellement son temps.

Encore plus rapidement consiste à utiliser le ParallelArray du framework fork-join (si vous avez un jeu de données suffisamment grand).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top