Pourquoi l'impression «B» est-elle beaucoup plus lente que l'impression «#»?

2749

J'ai généré deux matrices de 1000x 1000:

Première matrice: Oet #.
Deuxième matrice: Oet B.

En utilisant le code suivant, la première matrice a pris 8,52 secondes pour terminer:

Random r = new Random();
for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 1000; j++) {
        if(r.nextInt(4) == 0) {
            System.out.print("O");
        } else {
            System.out.print("#");
        }
    }

   System.out.println("");
 }

Avec ce code, la deuxième matrice a mis 259,152 secondes pour terminer:

Random r = new Random();
for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 1000; j++) {
        if(r.nextInt(4) == 0) {
            System.out.print("O");
        } else {
            System.out.print("B"); //only line changed
        }
    }

    System.out.println("");
}

Quelle est la raison derrière les temps d'exécution radicalement différents?


Comme suggéré dans les commentaires, l'impression ne System.out.print("#");prend que 7.8871quelques secondes, tandis que System.out.print("B");donne still printing....

Comme d'autres qui ont souligné que cela fonctionne normalement pour eux, j'ai essayé Ideone.com par exemple, et les deux morceaux de code s'exécutent à la même vitesse.

Conditions de test:

  • J'ai exécuté ce test à partir de Netbeans 7.2 , avec la sortie dans sa console
  • J'ai utilisé System.nanoTime()pour les mesures
Kuba Spatny
la source
62
Essayez de changer rand.nextInt (4) == 0 à i <250 pour éliminer l'effet du générateur aléatoire. Vous pourriez manquer d'entropie qui ralentit la génération aléatoire
fejese
3
Les deux semblent fonctionner pendant la même durée sur ma machine, ~ 4 secondes.
Sotirios Delimanolis
155
si vous suggérez que l'impression B prend plus de temps que l'impression # .... pourquoi n'essayez-vous pas d'imprimer tout B & all # plutôt que de vous fier à la variable aléatoire r
Kakarot
18
Sur la base de la réponse acceptée, vous n'avez apparemment pas essayé de l'exécuter avec une sortie redirigée vers un fichier ou / dev / null.
Barmar
24
@fejese, Random () n'est pas un rng cryptographique et n'utilise donc pas le pool d'entropie.
Divisez le

Réponses:

4073

La spéculation pure est que vous utilisez un terminal qui essaie de faire un habillage de mots plutôt qu'un habillage de caractères, et traite Bcomme un caractère de mot mais #comme un caractère non-mot. Ainsi, quand il atteint la fin d'une ligne et recherche un endroit pour rompre la ligne, il y voit #presque immédiatement et heureusement une pause; alors qu'avec le B, il doit continuer à chercher plus longtemps, et peut avoir plus de texte à encapsuler (ce qui peut être coûteux sur certains terminaux, par exemple, la sortie des espaces arrière, puis la sortie des espaces pour remplacer les lettres encapsulées).

Mais c'est de la pure spéculation.

TJ Crowder
la source
560
C'est en fait la bonne réponse! Ajouter un espace après l'avoir Brésolu.
Kuba Spatny
261
Il y a quelques réponses qui viennent d'une expérience durement apprise. TJ et moi (puisque nous sommes amis) avons grandi au temps de l'Apple] [et du zx80 / ​​81. Il n'y avait pas de retour à la ligne intégré à l'époque. Nous avons donc tous deux fini par écrire le nôtre - plus d'une fois. Et ces leçons restent avec vous, elles sont brûlées dans votre cerveau de lézard. Mais si vous vous êtes penché sur le code après cela, lorsque votre mot d'environnement encapsule tout, ou si vous le faites manuellement avant l'exécution, il est plus difficile de rencontrer les problèmes avec l'habillage de mots.
JockM
315
Déduction brillante. Mais nous devons généraliser à partir de cette leçon, et toujours mesurer les performances avec la sortie soit éliminée, dirigée vers / dev / null (NUL sous Windows) ou au moins vers un fichier. L'affichage sur n'importe quel type de console est généralement très coûteux, et déforme toujours les temps - même si ce n'est pas aussi déroutant que cela.
Bob Kerns
37
@MrLister: System.out.printlnne fait pas d'habillage de mots; la chose à laquelle il produisait était le retour à la ligne (et le blocage, donc il System.out.printlnfallait attendre).
TJ Crowder
35
@Chris - en fait, je dirai que ne pas les imprimer EST la solution, au problème d'obtenir des synchronisations précises de l'algorithme. Chaque fois que vous imprimez sur une console (quelle qu'elle soit), vous invoquez toutes sortes de traitements externes non liés à ce dont vous testez les performances. C'est un bug dans votre procédure de mesure, pur et simple. D'un autre côté, si vous ne voyez pas le problème comme une mesure, mais si vous comprenez la différence, alors oui, ne pas imprimer est une astuce de débogage. Cela se résume à quel problème essayez-vous de résoudre?
Bob Kerns
210

J'ai effectué des tests sur Eclipse vs Netbeans 8.0.2, tous deux avec Java version 1.8; J'ai utilisé System.nanoTime()pour les mesures.

Éclipse:

J'ai eu le même temps sur les deux cas - environ 1,564 secondes .

Netbeans:

  • Utilisation de "#": 1,536 secondes
  • Utilisation de "B": 44,164 secondes

Ainsi, il semble que Netbeans ait de mauvaises performances d'impression sur la console.

Après plus de recherches, j'ai réalisé que le problème est le retour à la ligne du tampon max de Netbeans (il n'est pas limité à la System.out.printlncommande), démontré par ce code:

for (int i = 0; i < 1000; i++) {
    long t1 = System.nanoTime();
    System.out.print("BBB......BBB"); \\<-contain 1000 "B"
    long t2 = System.nanoTime();
    System.out.println(t2-t1);
    System.out.println("");
}

Les résultats temporels sont inférieurs à 1 milliseconde à chaque itération, sauf à chaque cinquième itération , lorsque le résultat temporel est d'environ 225 millisecondes. Quelque chose comme (en nanosecondes):

BBB...31744
BBB...31744
BBB...31744
BBB...31744
BBB...226365807
BBB...31744
BBB...31744
BBB...31744
BBB...31744
BBB...226365807
.
.
.

Etc..

Sommaire:

  1. Eclipse fonctionne parfaitement avec "B"
  2. Netbeans a un problème de retour à la ligne qui peut être résolu (car le problème ne se produit pas dans l'éclipse) (sans ajouter d'espace après B ("B")).
Roy Shmuli
la source
32
pouvez-vous élaborer sur vos stratégies de recherche et qu'est-ce qui vous a finalement amené à découvrir que le saut de ligne était le coupable? (je suis curieux de vos compétences de détective, c'est!)
silph
12

Oui, le coupable est définitivement le coup de mots. Lorsque j'ai testé vos deux programmes, NetBeans IDE 8.2 m'a donné le résultat suivant.

  1. Première matrice: O et # = 6,03 secondes
  2. Deuxième matrice: O et B = 50,97 secondes

En regardant attentivement votre code, vous avez utilisé un saut de ligne à la fin de la première boucle. Mais vous n'avez utilisé aucun saut de ligne dans la deuxième boucle. Vous allez donc imprimer un mot de 1000 caractères dans la deuxième boucle. Cela provoque un problème de retour à la ligne. Si nous utilisons un caractère non mot "" après B, il ne faut que 5,35 secondes pour compiler le programme. Et si nous utilisons un saut de ligne dans la deuxième boucle après avoir passé 100 valeurs ou 50 valeurs, cela ne prend que 8,56 secondes et 7,05 secondes respectivement.

Random r = new Random();
for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 1000; j++) {
        if(r.nextInt(4) == 0) {
            System.out.print("O");
        } else {
            System.out.print("B");
        }
        if(j%100==0){               //Adding a line break in second loop      
            System.out.println();
        }                    
    }
    System.out.println("");                
}

Un autre conseil est de changer les paramètres de l'EDI NetBeans. Tout d'abord, allez dans Outils NetBeans et cliquez sur Options . Après cela, cliquez sur Editeur et accédez à l' onglet Formatage . Sélectionnez ensuite l' option N'importe où dans le retour à la ligne . Il faudra près de 6,24% moins de temps pour compiler le programme.

Paramètres de l'éditeur NetBeans

Abdul Alim Shakir
la source