49 votes

Analyse comparative Java - Pourquoi la deuxième boucle est-elle plus rapide?

Je suis curieux de savoir à ce sujet.

Je voulais vérifier la fonction qui a été plus rapide, j'ai donc créer un peu de code et je l'ai exécuté un grand nombre de fois.

public static void main(String[] args) {

        long ts;
        String c = "sgfrt34tdfg34";

        ts = System.currentTimeMillis();
        for (int k = 0; k < 10000000; k++) {
            c.getBytes();
        }
        System.out.println("t1->" + (System.currentTimeMillis() - ts));

        ts = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            Bytes.toBytes(c);
        }
        System.out.println("t2->" + (System.currentTimeMillis() - ts));

    }

La deuxième boucle est plus rapide, alors, j'ai pensé que les Octets de la classe de hadoop a été plus rapide que la fonction de la classe String. Ensuite, j'ai changé l'ordre des boucles et puis c.getBytes() a obtenu plus rapidement. J'ai exécuté plusieurs fois, et ma conclusion a été, je ne sais pas pourquoi, mais quelque chose se passe dans ma VM, après le premier code à exécuter pour que les résultats deviennent plus rapides pour la deuxième boucle.

61voto

Tim B Points 19851

C’est une question classique de benchmarking java. Hotspot / JIT / etc va compiler votre code au fur et à mesure de votre utilisation, pour qu'il soit plus rapide pendant l'exécution.

Faites d'abord le tour de la boucle au moins 3000 fois (10 000 sur un serveur ou sur 64 bits), puis faites vos mesures.

18voto

dasblinkenlight Points 264350

Vous savez qu'il ya quelque chose de mal, parce qu' Bytes.toBytes des appels c.getBytes en interne:

public static byte[] toBytes(String s) {
    try {
        return s.getBytes(HConstants.UTF8_ENCODING);
    } catch (UnsupportedEncodingException e) {
        LOG.error("UTF-8 not supported?", e);
        return null;
    }
}

La source est prise à partir d' ici. Cela vous indique que l'appel ne peut pas être plus rapide que l'appel direct - dans le meilleur des cas (c'est à dire si elle obtient inline), il aurait le même calendrier. En règle générale, cependant, vous vous attendez à être un peu plus lent, à cause de la faible surcharge dans l'appel d'une fonction.

C'est la classique le problème avec la micro-analyse comparative dans interprété, le garbage collector environnements avec des composants qui s'exécutent à l'arbitraire dans le temps, tels que les ramasseurs d'ordures. En plus de cela, il ya du matériel d'optimisation, telles que la mise en cache, qui faussent l'image. Comme le résultat, la meilleure façon de voir ce qui se passe est souvent de chercher à la source.

13voto

Peter Lawrey Points 229686

La deuxième boucle est plus rapide, de sorte que,

Lorsque vous exécutez une méthode au moins 10000 fois, il déclenche l' ensemble de la méthode pour être compilé. Cela signifie que votre deuxième boucle peut être

  • plus rapide, comme c'est déjà compilé la première fois que vous l'exécutez.
  • plus lent parce que quand optimisé il n'a pas de bonnes informations/compteurs sur la façon dont le code est exécuté.

La meilleure solution est de placer chaque tour de boucle dans une autre méthode, donc une boucle n'est pas d'optimiser l'autre ET d'exécuter cette opération plusieurs fois, en ignorant la première manche.

par exemple

for(int i = 0; i < 3; i++) {
    long time1 = doTest1();  // timed using System.nanoTime();
    long time2 = doTest2();
    System.out.printf("Test1 took %,d on average, Test2 took %,d on average%n",
        time1/RUNS, time2/RUNS);
}

6voto

Boann Points 11904

Très probablement, le code était toujours en cours de compilation ou n'était pas encore compilé au moment de l'exécution de la première boucle.

Enveloppez toute la méthode dans une boucle externe pour pouvoir exécuter les tests de performance plusieurs fois. Vous obtiendrez des résultats plus stables.

Lire: Compilation dynamique et mesure de la performance .

5voto

reindeer Points 1344

Il se peut simplement que vous allouiez autant d'espace aux objets avec getBytes () lors de vos appels, que JVM Garbage Collector démarre et nettoie les références inutilisées (pour extraire la corbeille).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X