2009-07-04 6 views

Antwort

25

welcher Reihenfolge sollte ich GzipOutputStream und BufferedOutputStream

Für Objektströme, fand ich, dass sowohl um die gzip-Stream für die gepufferte Strom Einwickeln Eingang und Ausgang war fast immer deutlich schneller . Je kleiner die Objekte, desto besser. Besser oder gleich in allen Fällen dann kein gepufferter Stream.

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

jedoch, für Text und gerade Byte-Streams, fand ich, dass es einen toss war - mit dem gzip Strom um den gepufferten Strom nur wenig besser zu sein. Aber besser in allen Fällen dann kein gepufferter Stream.

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

Ich lief jede Version 20 mal und abgeschnitten den ersten Lauf und gemittelt den Rest. Ich habe auch gepuffert-gzip gepuffert, was etwas besser für Objekte und schlechter für Text war. Ich habe überhaupt nicht mit Puffergrößen gespielt.


Für die Objektströme getestet I 2 serialisierten Objektdateien in dem 10s Megabyte.Für die größere Datei (38 MB) war es 85% schneller beim Lesen (0,7 gegenüber 5,6 Sekunden), aber tatsächlich etwas langsamer beim Schreiben (5,9 gegenüber 5,7 Sekunden). Diese Objekte hatten einige große Arrays, was möglicherweise größere Schreibvorgänge bedeutet.

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

Für die kleinere Datei (18MB), war es 75% schneller zum Lesen (1,6 im Vergleich zu 6,1 Sekunden) und 40% schneller zum Schreiben (2,8 im Vergleich zu 4,7 Sekunden). Es enthielt eine große Anzahl kleiner Objekte.

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

Für den Text-Leser/Schreiber ich eine 64mb CSV-Textdatei verwendet. Der gzip-Stream um den gepufferten Stream war 11% schneller beim Lesen (950 gegenüber 1070 Millisekunden) und etwas schneller beim Schreiben (7,9 gegenüber 8,1 Sekunden).

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

Ich schlage vor, Sie versuchen einen einfachen Benchmark zu Zeit wie lange es dauert, eine große Datei zu komprimieren und zu sehen, ob es viel Unterschied macht. GzipOutputStream hat Pufferung, aber es ist ein kleinerer Puffer. Ich würde das erste mit einem 64K-Puffer machen, aber Sie könnten feststellen, dass beides besser ist.

6

Die Pufferung hilft, wenn das ultimative Ziel der Daten am besten in größeren Blöcken gelesen/geschrieben wird, als Ihr Code es sonst tun würde. Daher möchten Sie, dass die Pufferung so nahe wie möglich an dem Ort liegt, an dem größere Blöcke vorhanden sein sollen. In Ihren Beispielen ist das das "...", also verpacken Sie den BufferedOutputStream mit GzipOutputStream. Passen Sie die BufferedOutputStream-Puffergröße so an, dass sie mit den Tests übereinstimmt, die am besten mit dem Ziel funktionieren.

Ich bezweifle die BufferedOutputStream auf der Außenseite würde viel, wenn überhaupt, über keine explizite Pufferung helfen. Warum nicht? Der GzipOutputStream wird seine write() s auf "..." in Blöcken gleicher Größe ausführen, unabhängig davon, ob die externe Pufferung vorhanden ist oder nicht. Es gibt also keine Optimierung für "..." möglich; Du bist fest mit welchen Größen GzipOutputStream write() s.

Beachten Sie auch, dass Sie den Arbeitsspeicher effizienter nutzen, indem Sie die komprimierten Daten statt der unkomprimierten Daten puffern. Wenn Ihre Daten oft eine 6X-Komprimierung erreichen, entspricht der "innere" Puffer einem "externen" Puffer 6X, der so groß ist.

0

Lesen Sie das Javadoc, und Sie werden feststellen, dass BIS verwendet wird, um Bytes aus einer ursprünglichen Quelle gelesen zu puffern. Sobald Sie die rohen Bytes erhalten haben, die Sie komprimieren möchten, verpacken Sie BIS mit einem GIS. Es macht keinen Sinn, die Ausgabe von einem GZIP zu puffern, weil man darüber nachdenken muss, wie man GZIP puffern kann, wer wird das tun?

new GzipInputStream(new BufferedInputStream (new FileInputXXX 
+2

"Sie möchten sie komprimieren, sodass Sie BIS mit einem GIS umbrechen" - GIS komprimiert nicht. Es dekomprimiert. FWIW Ich habe Mühe, Ihren allgemeinen Punkt im letzten Teil Ihrer Antwort zu verstehen. – bacar

2

Normalerweise wollen Sie einen Puffer zu Ihrer Outputstream schließen (vorausgesetzt, das ist, was ... repräsentiert) zu viele Anrufe in das Betriebssystem und häufig Plattenzugriff zu vermeiden. Wenn Sie jedoch viele kleine Stücke in den GZIPOutputStream schreiben, können Sie auch von einem Puffer um GZIPOS profitieren. Der Grund dafür, dass die Schreibmethode in GZIPOS synchronisiert ist, führt auch zu einigen anderen synchronisierten Aufrufen und einigen nativen (JNI-) Aufrufen (um den CRC32 zu aktualisieren und die eigentliche Komprimierung durchzuführen). Diese fügen zusätzlichen Overhead pro Anruf hinzu. In diesem Fall würde ich sagen, dass Sie von beiden Puffern profitieren werden.

17

GZIPOutputStream kommt bereits mit einem eingebauten Puffer. Es ist also nicht notwendig, einen BufferedOutputStream direkt daneben in der Kette zu platzieren. Die ausgezeichnete Antwort von gojomo liefert bereits eine Anleitung, wo der Puffer platziert werden soll.

Die Standardpuffergröße für GZIPOutputStream beträgt nur 512 Byte. Sie sollten sie daher über den Konstruktorparameter auf 8K oder sogar 64 KB erhöhen. Die Standardpuffergröße für BufferedOutputStream beträgt 8 KB. Daher können Sie einen Vorteil messen, wenn Sie den Standard-GZIPOutputStream und BufferedOutputStream kombinieren. Dieser Vorteil kann auch erreicht werden, indem der eingebaute Puffer des GZIPOutputStreams richtig dimensioniert wird.

Also, um Ihre Frage zu beantworten: "Sollte ich BufferedOutputStream überhaupt verwenden?" → Nein, in Ihrem Fall sollten Sie es nicht verwenden, sondern den Puffer des GZIPOutputStream auf mindestens 8K setzen.

Verwandte Themen