Perché la stampa "B" è notevolmente più lenta della stampa "#"?


2749

Ho generato due matrici di 1000x 1000:

Prima matrice: Oe #.
Seconda matrice: Oe B.

Utilizzando il seguente codice, il completamento della prima matrice ha richiesto 8,52 secondi:

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("");
 }

Con questo codice, il completamento della seconda matrice ha richiesto 259.152 secondi:

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("");
}

Qual è la ragione dietro i tempi di esecuzione drammaticamente diversi?


Come suggerito nei commenti, la stampa System.out.print("#");richiede solo 7.8871pochi secondi, mentre System.out.print("B");still printing....

Come altri che hanno sottolineato che funziona normalmente per loro, ho provato Ideone.com per esempio, ed entrambi i pezzi di codice vengono eseguiti alla stessa velocità.

Condizioni di prova:

  • Ho eseguito questo test da Netbeans 7.2 , con l'output nella sua console
  • Ho usato System.nanoTime()per le misurazioni

62
Prova a cambiare rand.nextInt (4) == 0 in i <250 per eliminare l'effetto del generatore casuale. Potresti
rimanere

3
Entrambi sembrano funzionare per la stessa quantità di tempo sulla mia macchina, ~ 4 secondi.
Sotirios Delimanolis,

155
se stai suggerendo che la stampa di B richiede più tempo rispetto alla stampa di # .... perché non provi a stampare tutti i B & all # invece di affidarti alla variabile casuale r
Kakarot,

18
Sulla base della risposta accettata, apparentemente non hai provato a eseguirlo con l'output reindirizzato a un file o / dev / null.
Barmar,

24
@fejese, Random () non è un crittografo rng e quindi non utilizza il pool di entropia.
Dividi il

Risposte:


4073

La pura speculazione è che stai usando un terminale che tenta di eseguire il wrapping delle parole anziché il wrapping dei caratteri e considera Bcome un carattere di parola ma #come un carattere non di parola. Quindi quando raggiunge la fine di una linea e cerca un posto per spezzare la linea, vede un #quasi immediatamente e felicemente si rompe lì; mentre con il B, deve continuare a cercare più a lungo, e potrebbe avere più testo da avvolgere (che può essere costoso su alcuni terminali, ad esempio, emettere backspaces, quindi emettere spazi per sovrascrivere le lettere che vengono racchiuse).

Ma questa è pura speculazione.


560
Questa è in realtà la risposta corretta! Aggiungendo uno spazio dopo Baverlo risolto.
Kuba Spatny,

261
Ci sono alcune risposte che provengono da esperienze dure. TJ e io (poiché siamo amici) siamo cresciuti ai tempi della Mela] [e della zx80 / ​​81. Allora non esisteva un ritorno a capo automatico. Quindi entrambi abbiamo finito per scrivere il nostro - più di una volta. E quelle lezioni rimangono con te, vengono bruciate nel tuo cervello di lucertola. Ma se ti sei appoggiato al codice dopo quello, quando la parola del tuo ambiente avvolge tutto o lo fai manualmente prima del runtime, è più difficile imbattersi nei problemi con il ritorno a capo automatico.
JockM,

315
Deduzione brillante. Ma dovremmo generalizzare da questa lezione e misurare sempre le prestazioni con l'output sia eliminato, diretto a / dev / null (NUL su Windows) o almeno a un file. La visualizzazione su qualsiasi tipo di console è in genere IO molto costosa e distorce sempre i tempi, anche se non in modo così confuso.
Bob Kerns,

37
@MrLister: System.out.printlnnon esegue il wrapping di parole ; la cosa a cui stava uscendo era fare il wrapping delle parole (e il blocco, quindi System.out.printlndovevo aspettare).
TJ Crowder,

35
@ Chris - in realtà, sosterrò che non stamparli è la soluzione, al problema di ottenere tempi precisi dell'algoritmo. Ogni volta che si stampa su una console (di qualsiasi tipo), si invoca qualsiasi tipo di elaborazione esterna non correlata a ciò di cui si sta testando le prestazioni. È un bug nella tua procedura di misurazione, puro e semplice. D'altra parte, se vedi il problema non come una misura, ma capendo la discrepanza, allora sì, non stampare è un trucco di debug. Si riduce a quale problema stai cercando di risolvere?
Bob Kerns

210

Ho eseguito test su Eclipse vs Netbeans 8.0.2, entrambi con Java versione 1.8; Ho usato System.nanoTime()per le misurazioni.

Eclisse:

Ho avuto lo stesso tempo in entrambi i casi , circa 1,564 secondi .

Netbeans:

  • Utilizzando "#": 1,536 secondi
  • Usando "B": 44.164 secondi

Quindi, sembra che Netbeans abbia cattive prestazioni sulla stampa su console.

Dopo ulteriori ricerche mi sono reso conto che il problema è il ritorno a capo del buffer massimo di Netbeans (non è limitato al System.out.printlncomando), dimostrato da questo codice:

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("");
}

I risultati temporali sono meno di 1 millisecondo per ogni iterazione tranne ogni quinta iterazione , quando il risultato temporale è di circa 225 millisecondi. Qualcosa di simile (in nanosecondi):

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

E così via..

Sommario:

  1. Eclipse funziona perfettamente con "B"
  2. Netbeans ha un problema di avvolgimento della linea che può essere risolto (perché il problema non si verifica in eclissi) (senza aggiungere spazio dopo B ("B")).

32
puoi approfondire le tue strategie di ricerca e poi cosa ti ha portato alla fine a scoprire che il colpevole era il wrapping? (Sono curioso delle tue capacità investigative, cioè!)
silph

12

Sì, il colpevole è decisamente avvolgente. Quando ho testato i tuoi due programmi, NetBeans IDE 8.2 mi ha dato il seguente risultato.

  1. Prima matrice: O e # = 6,03 secondi
  2. Seconda matrice: O e B = 50,97 secondi

Esaminando attentamente il codice, è stata utilizzata un'interruzione di riga alla fine del primo ciclo. Ma non hai usato nessuna interruzione di linea nel secondo loop. Quindi stai per stampare una parola con 1000 caratteri nel secondo ciclo. Ciò causa un problema di a capo automatico. Se utilizziamo un carattere non "" dopo B, occorrono solo 5,35 secondi per compilare il programma. E se usiamo un'interruzione di riga nel secondo loop dopo aver superato 100 o 50 valori, occorrono rispettivamente solo 8,56 secondi e 7,05 secondi .

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 altro consiglio è quello di modificare le impostazioni dell'IDE NetBeans. Prima di tutto, vai su Strumenti NetBeans e fai clic su Opzioni . Successivamente fai clic su Editor e vai alla scheda Formattazione . Quindi selezionare Ovunque in linea Wrap Opzione. Ci vorrà quasi il 6,24% in meno di tempo per compilare il programma.

Impostazioni dell'editor NetBeans

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.