2009-07-04 11 views

risposta

25

Quale ordine dovrei usare GzipOutputStream e BufferedOutputStream

Per i flussi di oggetti, ho scoperto che avvolgendo il flusso tamponato intorno al torrente gzip sia per l'input e l'output era quasi sempre significativamente più veloce . Più piccoli sono gli oggetti, meglio è stato. Migliore o uguale in tutti i casi quindi nessun flusso bufferizzato.

ois = new ObjectInputStream(new BufferedInputStream(new GZIPInputStream(fis))); 
oos = new ObjectOutputStream(new BufferedOutputStream(new GZIPOutputStream(fos))); 

Tuttavia, per il testo e flussi di byte dritto, ho scoperto che si trattava di una scossa in su - con il flusso di gzip intorno al torrente tamponata essendo solo leggermente migliore. Ma meglio in tutti i casi quindi nessun flusso bufferizzato.

reader = new InputStreamReader(new GZIPInputStream(new BufferedInputStream(fis))); 
writer = new OutputStreamWriter(new GZIPOutputStream(new BufferedOutputStream(fos))); 

ho corse ogni versione 20 volte e tagliare la prima esecuzione e in media il resto. Ho anche provato buffered-gzip-buffered che era leggermente migliore per gli oggetti e peggio per il testo. Non ho giocato affatto con le dimensioni del buffer.


Per i flussi di oggetti, ho testato 2 file oggetto serializzati nei 10s di megabyte.Per il file più grande (38 MB), la lettura era più veloce dell'85% (0,7 contro 5,6 secondi), ma in realtà leggermente più lenta per la scrittura (5,9 contro 5,7 secondi). Questi oggetti avevano alcuni grandi array in essi che potevano significare più grandi scritture.

method  crc  date time compressed uncompressed ratio 
defla eb338650 May 19 16:59  14027543  38366001 63.4% 

Per il file più piccolo (18MB), è stato più veloce del 75% per la lettura (1,6 rispetto a 6,1 secondi) e il 40% più veloce per la scrittura (2,8 rispetto a 4,7 secondi). Conteneva un gran numero di piccoli oggetti.

method  crc  date time compressed uncompressed ratio 
defla 92c9d529 May 19 16:56  6676006  17890857 62.7% 

Per il lettore di testo/scrittore ho usato un file di testo csv 64mb. Il flusso gzip attorno al flusso bufferizzato era più veloce dell'11% per la lettura (950 contro 1070 millisecondi) e leggermente più veloce durante la scrittura (7,9 contro 8,1 secondi).

method  crc  date time compressed uncompressed ratio 
defla c6b72e34 May 20 09:16  22560860  63465800 64.5% 
2

Ti suggerisco di provare un semplice benchmark per calcolare quanto tempo ci vuole per comprimere un file di grandi dimensioni e vedere se fa molta differenza. GzipOutputStream ha un buffer ma è un buffer più piccolo. Farei il primo con un buffer da 64K, ma potresti scoprire che fare entrambi è meglio.

6

Il buffering aiuta quando la destinazione finale dei dati è meglio leggibile/scritta in blocchi più grandi di quanto il vostro codice non lo spingerebbe altrimenti. Quindi, in generale, si desidera che il buffering sia il più vicino possibile al posto che desidera. Nei tuoi esempi, questo è il "..." eletto, quindi avvolgi BufferedOutputStream con GzipOutputStream. E, aggiusta la dimensione del buffer BufferedOutputStream in modo che corrisponda a ciò che i test dimostrano che funzionano meglio con la destinazione.

Dubito che BufferedOutputStream all'esterno possa essere di grande aiuto, se non del tutto, senza buffer esplicito. Perchè no? GzipOutputStream farà il suo write() s a "..." nei blocchi della stessa dimensione se il buffering esterno è presente o meno. Quindi non c'è ottimizzazione per "..." possibile; sei bloccato con quali dimensioni GzipOutputStream write() s.

Nota anche che stai utilizzando la memoria in modo più efficiente tamponando i dati compressi piuttosto che i dati non compressi. Se i tuoi dati spesso raggiungono una compressione 6X, il buffer 'inside' è equivalente a un buffer 'outside' 6X grande.

0

Leggi javadoc e scoprirai che BIS è utilizzato per bufferare i byte letti da qualche fonte originale. Una volta ottenuti i byte grezzi, si desidera comprimerli in modo da avvolgere BIS con un GIS. Non ha senso bufferizzare l'output da un GZIP, perché è necessario pensare a cosa dire del buffering di GZIP, chi lo farà?

new GzipInputStream(new BufferedInputStream (new FileInputXXX 
+2

"si vuole comprimere loro in modo da avvolgere BIS con un GIS" - GIS non comprime. Si decomprime. FWIW Sto faticando a capire il tuo punto generale nell'ultima parte della tua risposta. – bacar

2

Normalmente si desidera un buffer vicino al tuo FileOutputStream (supponendo che è quello che ... rappresenta) per evitare troppe chiamate verso il sistema operativo e l'accesso al disco frequenti. Tuttavia, se stai scrivendo un sacco di piccoli pezzi su GZIPOutputStream, potresti trarre vantaggio da un buffer attorno a GZIPOS. Il motivo è il metodo di scrittura nel GZIPOS è sincronizzato e porta anche ad alcune altre chiamate sincronizzati e un paio di nativo (JNI) chiama (per aggiornare il CRC32 e fare la compressione effettiva). Tutto ciò aggiunge un sovraccarico supplementare per chiamata. Quindi in tal caso direi che trarrai beneficio da entrambi i buffer.

17

GZIPOutputStream viene fornito già con un tampone incorporata. Quindi, non c'è bisogno di mettere un BufferedOutputStream proprio accanto ad esso nella catena. L'eccellente risposta di gojomo fornisce già alcune indicazioni su dove posizionare il buffer.

La dimensione del buffer predefinita per GZIPOutputStream è solo 512 byte, quindi sarà necessario aumentarla a 8K o addirittura a 64K tramite il parametro costruttore. La dimensione del buffer predefinita per BufferedOutputStream è 8K, motivo per cui è possibile misurare un vantaggio quando si combinano GZIPOutputStream e BufferedOutputStream predefiniti. Questo vantaggio può anche essere ottenuto dimensionando correttamente il buffer integrato di GZIPOutputStream.

Quindi, per rispondere alla tua domanda: "Dovrei usare BufferedOutputStream a tutti?" → No, nel tuo caso, non si dovrebbe usare, ma invece impostare il buffer della GZIPOutputStream ad almeno 8K.