Pergunta

Alguém pode recomendar se eu deveria fazer algo como:

os = new GzipOutputStream(new BufferedOutputStream(...));

ou

os = new BufferedOutputStream(new GzipOutputStream(...));

O que é mais eficiente? Devo usar BufferedOutputStream em tudo?

Foi útil?

Solução

O que ordem devo usar GzipOutputStream e BufferedOutputStream

Para fluxos de objeto, descobri que envolver o fluxo de tampão ao redor do fluxo de gzip para entrada e saída era quase sempre significativamente mais rápido. Quanto menor os objetos, o melhor desta fez. Melhor ou o mesmo em todos os casos, em seguida, fluxo não tamponada.

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

No entanto , para texto e fluxos de bytes em linha reta, eu achei que era um lance acima - com o fluxo gzip ao redor do córrego tamponada sendo apenas um pouco melhor. Mas é melhor em todos os casos, em seguida, fluxo não tamponada.

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

Eu corri cada versão 20 vezes e cortou a primeira execução e média do resto. Eu também tentei-tampão gzip tamponada que foi ligeiramente melhor para objetos e pior para o texto. Eu não jogar com tamanhos de buffer em tudo.


Para os fluxos de objetos, eu testei 2 arquivos de objetos serializados nos 10s de megabytes. Para o arquivo maior (38MB), foi 85% mais rápido em leitura (0,7 contra 5,6 segundos), mas, na verdade, um pouco mais lento para escrever (5,9 contra 5,7 segundos). Esses objetos tinham algumas grandes matrizes neles que pode ter significado escreve maiores.

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

Para o arquivo menor (18MB), foi 75% mais rápido para ler (1,6 contra 6,1 segundos) e 40% mais rápido para escrever (2,8 contra 4,7 segundos). Ele continha um grande número de pequenos objetos.

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

Para o leitor de texto / escritor eu usei um arquivo de texto CSV 64mb. O fluxo gzip ao redor do córrego tamponada foi 11% mais rápido para leitura (950 contra 1.070 milissegundos) e um pouco mais rápido ao escrever (7,9 contra 8,1 segundos).

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

Outras dicas

GZIPOutputStream já vem com um buffer interno. Assim, não há necessidade de colocar um BufferedOutputStream bem próximo a ela na cadeia. excelente resposta de gojomo já fornece algumas orientações sobre onde colocar o tampão.

O tamanho do buffer padrão para GZIPOutputStream é de apenas 512 bytes, então você vai querer aumentá-la para 8K ou mesmo 64K através do parâmetro construtor. O tamanho do buffer padrão para BufferedOutputStream é 8K, razão pela qual você pode medir uma vantagem quando se combina o padrão GZIPOutputStream e BufferedOutputStream. Essa vantagem também pode ser alcançado por dimensionamento adequado do GZIPOutputStream built-in buffer.

Assim, para responder sua pergunta: "Devo usar BufferedOutputStream em tudo?" ? Não, no seu caso, você não deve usá-lo, mas em vez disso definir o buffer do GZIPOutputStream a pelo menos 8K.

O buffer de ajuda quando o destino final dos dados é melhor leitura / escrita em pedaços maiores do que o seu código, caso contrário empurrá-lo. Então, você geralmente deseja que o buffer para ser o mais próximo ao lugar que-quer-maiores-pedaços. Em seus exemplos, essa é a elidido "...", então embrulhar o BufferedOutputStream com o GZIPOutputStream. E, sintonizar o BufferedOutputStream buffer de tamanho para coincidir com o teste mostra funciona melhor com o destino.

Eu duvido que o BufferedOutputStream no exterior ajudaria muito, se em tudo, buffering sobre não explícito. Por que não? O GZIPOutputStream fará seu write () é a "..." no mesmo tamanho pedaços se o buffer fora está presente ou não. Portanto, não há otimização de "..." possível; você está preso com que tamanhos GZIPOutputStream write () s.

Note também que você está usando a memória de forma mais eficiente por amortecer os dados comprimidos em vez dos dados não comprimidos. Se os seus dados, muitas vezes acheives compressão 6X, o buffer 'dentro' é equivalente a um 'fora' tampão 6X tão grande.

Normalmente, você quer um tampão perto de seu FileOutputStream (assumindo que é o que ... representa) para evitar muitas chamadas para o sistema operacional e acesso ao disco frequente. No entanto, se você estiver escrevendo um monte de pequenos pedaços ao GZIPOutputStream que você pode beneficiar de um tampão em redor GZIPOS também. A razão é o método de gravação em GZIPOS é sincronizada e também leva a algumas outras chamadas sincronizados e um par de chamadas nativas (JNI) (para atualizar o CRC32 e fazer a compressão real). Estes todos adicionar sobrecarga adicional por chamada. Então, nesse caso eu diria que você vai se beneficiar de ambos os buffers.

Eu sugiro que você tente uma referência simples ao tempo quanto tempo leva para compactar um arquivo grande e ver se ele faz muita diferença. GZIPOutputStream tem buffer mas é um buffer menor. Eu faria o primeiro com um tampão de 64K, mas você pode achar que fazendo as duas coisas é melhor.

Leia o javadoc, e você vai descobrir que o BIS é usado para amortecer bytes lidos de alguma fonte original. Depois de conseguir os bytes brutos que você quer compactá-los para que você enrole BIS com um GIS. Não faz sentido para tamponar a saída de um GZIP, porque é preciso pensar o que dizer de tamponamento GZIP, quem é que vai fazer isso?

new GzipInputStream( new BufferedInputStream ( new FileInputXXX
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top