2009-07-04 12 views

Respuesta

25

Qué orden debo utilizar GzipOutputStream y BufferedOutputStream

Para flujos de objetos, me encontré con que envolver la corriente tampón alrededor de la corriente gzip tanto de entrada como de salida era casi siempre significativamente más rápido . Cuanto más pequeños sean los objetos, mejor será esto. Mejor o igual en todos los casos, luego no hay flujo amortiguado.

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

Sin embargo, para el texto y flujos de bytes consecutivos, me pareció que era un cara o cruz - con la corriente gzip alrededor de la corriente tamponada siendo sólo un poco mejor. Pero mejor en todos los casos, entonces no hay flujo amortiguado.

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

que corrió cada versión 20 veces y le cortó la primera pasada y promedió el resto. También probé buffer-gzip-buffer que era ligeramente mejor para objetos y peor para texto. No jugué con tamaños de búfer en absoluto.


Para las secuencias de objetos, probé 2 archivos de objetos serializados en 10s de megabytes.Para el archivo más grande (38 mb), fue 85% más rápido en la lectura (0,7 frente a 5,6 segundos) pero en realidad un poco más lento para la escritura (5,9 frente a 5,7 segundos). Estos objetos tenían algunas matrices grandes que pueden haber significado escrituras más grandes.

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

Para el archivo más pequeño (18mb), era 75% más rápido para leer (1,6 frente a 6,1 segundos) y un 40% más rápido para escribir (2,8 frente a 4,7 segundos). Contenía una gran cantidad de objetos pequeños.

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

Para el lector de texto/escritor he utilizado un archivo de texto CSV 64mb. La secuencia gzip alrededor de la secuencia amortiguada fue 11% más rápida para la lectura (950 frente a 1070 milisegundos) y ligeramente más rápida al escribir (7.9 versus 8.1 segundos).

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

Le sugiero que pruebe con un punto de referencia simple para medir el tiempo que lleva comprimir un archivo grande y ver si hace mucha diferencia. GzipOutputStream tiene almacenamiento en búfer, pero es un búfer más pequeño. Haría lo primero con un buffer de 64K, pero podría encontrar que hacer ambas cosas es mejor.

6

El almacenamiento en búfer ayuda cuando el destino final de los datos es mejor leído/escrito en trozos más grandes de lo que su código de otro modo lo impulsaría. Por lo tanto, generalmente desea que el almacenamiento en búfer sea lo más parecido posible al lugar en el que desea trozos más grandes. En sus ejemplos, ese es el "..." eliminado, entonces envuelva el BufferedOutputStream con el GzipOutputStream. Y ajuste el tamaño del búfer BufferedOutputStream para que coincida con las pruebas que funcionan mejor con el destino.

Dudo que el BufferedOutputStream en el exterior ayude mucho, si es que lo hace, sobre ningún almacenamiento en búfer explícito. Por qué no? El GzipOutputStream hará su escritura() s a "..." en trozos del mismo tamaño, ya sea que el almacenamiento en el exterior esté presente o no. Entonces no hay optimización para "..." posible; estás atascado con qué tamaños escribe GzipOutputStream() s.

Tenga en cuenta también que está utilizando la memoria de forma más eficiente mediante el almacenamiento en búfer de los datos comprimidos en lugar de los datos sin comprimir. Si sus datos a menudo obtienen una compresión de 6X, el búfer 'interno' es equivalente a un búfer 'externo' 6 veces mayor.

0

Lea el javadoc, y descubrirá que BIS se utiliza para almacenar en búfer los bytes leídos de alguna fuente original. Una vez que obtenga los bytes sin procesar, los quiere comprimir para que ajuste BIS con un GIS. No tiene sentido almacenar en búfer la salida de un GZIP, porque hay que pensar qué hay sobre el almacenamiento en búfer de GZIP, ¿quién va a hacer eso?

new GzipInputStream(new BufferedInputStream (new FileInputXXX 
+2

"desea comprimirlos para que ajuste BIS con un GIS" - GIS no comprime. Descomprime. FWIW Estoy luchando por comprender su punto general en la última parte de su respuesta. – bacar

2

Normalmente quieren una memoria intermedia cerca de su FileOutputStream (suponiendo que es lo que representa ...) para evitar demasiadas llamadas en el sistema operativo y el acceso al disco frecuente. Sin embargo, si escribe un montón de fragmentos pequeños en GZIPOutputStream, también podría beneficiarse de un buffer alrededor de GZIPOS. La razón por la cual el método de escritura en GZIPOS está sincronizado y también conduce a algunas otras llamadas sincronizadas y un par de llamadas nativas (JNI) (para actualizar el CRC32 y hacer la compresión real). Todos estos agregan gastos adicionales por llamada. Entonces, en ese caso, diría que se beneficiarán de ambos buffers.

17

GZIPOutputStream ya viene con un buffer integrado. Por lo tanto, no es necesario colocar un BufferedOutputStream al lado de la cadena. La excelente respuesta de Gojomo ya proporciona alguna guía sobre dónde colocar el buffer.

El tamaño del búfer predeterminado para GZIPOutputStream es de solo 512 bytes, por lo que querrá aumentarlo a 8K o incluso a 64K a través del parámetro de constructor. El tamaño de búfer predeterminado para BufferedOutputStream es 8K, por lo que puede medir una ventaja al combinar el GZIPOutputStream predeterminado y BufferedOutputStream. Esa ventaja también se puede lograr dimensionando adecuadamente el buffer incorporado de GZIPOutputStream.

Por lo tanto, para responder a su pregunta: "¿Debo usar BufferedOutputStream en absoluto?" → No, en su caso, no debe usarlo, sino que debe configurar el búfer de GZIPOutputStream en al menos 8K.

Cuestiones relacionadas