java - ¿En qué orden debo usar GzipOutputStream y BufferedOutputStream?
(6)
¿Alguien puede recomendar si debo hacer algo como:
os = new GzipOutputStream(new BufferedOutputStream(...));
o
os = new BufferedOutputStream(new GzipOutputStream(...));
¿Cuál es más eficiente? ¿Debo usar BufferedOutputStream en absoluto?
¿En qué orden debo usar
GzipOutputStream
yBufferedOutputStream
Para las secuencias de objetos, descubrí que envolver la secuencia en búfer alrededor de la secuencia gzip tanto para la entrada como para la salida era casi siempre mucho más rápido. Cuanto más pequeños son los objetos, mejor lo hizo. Mejor o igual en todos los casos, entonces no hay flujo de búfer.
ois = new ObjectInputStream(new BufferedInputStream(new GZIPInputStream(fis)));
oos = new ObjectOutputStream(new BufferedOutputStream(new GZIPOutputStream(fos)));
Sin embargo , para las corrientes de texto y de bytes directos, descubrí que era un lanzamiento, con la secuencia de gzip alrededor de la secuencia con búfer solo un poco mejor. Pero mejor en todos los casos, entonces no hay flujo de búfer.
reader = new InputStreamReader(new GZIPInputStream(new BufferedInputStream(fis)));
writer = new OutputStreamWriter(new GZIPOutputStream(new BufferedOutputStream(fos)));
Ejecuté cada versión 20 veces, corté la primera ejecución y promedié el resto. También probé buffered-gzip-buffered que fue ligeramente mejor para los objetos y peor para el texto. No jugué con tamanos de búfer en absoluto.
Para las secuencias de objetos, probé 2 archivos de objetos serializados en los 10s de megabytes. Para el archivo más grande (38 mb), fue 85% más rápido en lectura (0.7 contra 5.6 segundos) pero en realidad un poco más lento para escribir (5.9 contra 5.7 segundos). Estos objetos tenían algunos arreglos grandes en ellos 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 (18 mb), fue 75% más rápido para lectura (1.6 versus 6.1 segundos) y 40% más rápido para escribir (2.8 versus 4.7 segundos). Contenía un gran número de pequeños objetos.
method crc date time compressed uncompressed ratio
defla 92c9d529 May 19 16:56 6676006 17890857 62.7%
Para el lector / escritor de texto usé un archivo de texto csv de 64 mb. La corriente de gzip alrededor de la corriente con buffer fue 11% más rápida para la lectura (950 versus 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%
El almacenamiento en búfer ayuda cuando el destino final de los datos se lee / escribe mejor en partes más grandes de lo que su código de otro modo lo empujaría. Por lo tanto, por lo general, desea que el búfer esté lo más cerca posible de los trozos más grandes de place-that-Want-Want. En sus ejemplos, ese es el elidido "...", así que envuelva el BufferedOutputStream con el GzipOutputStream. Y, sintonice el tamaño del búfer BufferedOutputStream para que coincida con lo que muestra la prueba que funciona mejor con el destino.
Dudo que el BufferedOutputStream en el exterior ayude mucho, si es que lo hace, en lugar de ningún búfer explícito. Por qué no? El GzipOutputStream hará su escritura () s a "..." en trozos del mismo tamaño si el búfer externo está presente o no. Así que 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 manera más eficiente al almacenar en búfer los datos comprimidos en lugar de los datos no comprimidos. Si sus datos a menudo alcanzan la compresión 6X, el búfer ''interior'' es equivalente a un búfer ''externo'' 6X tan grande.
Le sugiero que pruebe un punto de referencia simple para calcular cuánto tiempo lleva comprimir un archivo grande y ver si hay mucha diferencia. GzipOutputStream tiene buffering pero es un buffer más pequeño. Haría lo primero con un búfer de 64K, pero podría encontrar que hacer ambas cosas es mejor.
Lea el javadoc, y descubrirá que BIS se utiliza para almacenar bytes de lectura de alguna fuente original. Una vez que obtenga los bytes en bruto, desea comprimirlos para que pueda ajustar BIS con un SIG. No tiene sentido amortiguar la salida de un GZIP, porque uno tiene que pensar qué pasa con el almacenamiento en GZIP, ¿quién va a hacer eso?
new GzipInputStream( new BufferedInputStream ( new FileInputXXX
Normalmente, desea un búfer cerca de su FileOutputStream (suponiendo que eso es lo que ... representa) para evitar demasiadas llamadas al sistema operativo y el acceso frecuente al disco. Sin embargo, si está escribiendo muchos fragmentos pequeños en GZIPOutputStream, también podría beneficiarse de un búfer alrededor de GZIPOS. La razón es que 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 realizar la compresión real). Todos estos añaden gastos adicionales por llamada. Entonces, en ese caso, diría que te beneficiarás de ambos buffers.
GZIPOutputStream ya viene con un búfer incorporado. Por lo tanto, no hay necesidad de poner un BufferedOutputStream justo al lado en la cadena. La excelente respuesta de gojomo ya proporciona una guía sobre dónde colocar el búfer.
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 constructor. El tamaño del búfer predeterminado para BufferedOutputStream es 8K, por lo que puede medir una ventaja al combinar el GZIPOutputStream y BufferedOutputStream predeterminados. Esa ventaja también se puede lograr al dimensionar correctamente el búfer incorporado de GZIPOutputStream.
Entonces, para responder a tu pregunta: "¿Debo usar BufferedOutputStream?" → No, en su caso, no debe usarlo, sino que debe configurar el búfer de GZIPOutputStream en al menos 8K.