Подтвердить что ты не робот

Какой порядок я должен использовать GzipOutputStream и BufferedOutputStream

Может ли кто-нибудь порекомендовать мне сделать что-то вроде:

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

или

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

Что более эффективно? Должен ли я использовать BufferedOutputStream вообще?

4b9b3361

Ответ 1

Какой порядок следует использовать GzipOutputStream и BufferedOutputStream

Для потоков объектов я обнаружил, что перенос буферизованного потока вокруг потока gzip для ввода и вывода почти всегда значительно быстрее. Чем меньше объекты, тем лучше. Лучше или одинаково во всех случаях, тогда нет буферизованного потока.

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

Однако для текстовых и прямых байтовых потоков я обнаружил, что это был взлет - поток gzip вокруг буферизованного потока был только немного лучше. Но лучше во всех случаях нет буферизованного потока.

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

Я запускал каждую версию 20 раз и прерывал первый прогон и усреднял остальные. Я также попробовал буферизованный-gzip-буфер, который был немного лучше для объектов и хуже для текста. Я вообще не играл с размерами буфера.


Для потоков объектов я протестировал 2 сериализованных объектных файла в 10 мегабайтах. Для более крупного файла (38 Мб) он был на 85% быстрее при чтении (0,7 против 5,6 секунды), но на самом деле он немного медленнее для записи (5,9 против 5,7 секунды). Эти объекты имели в них несколько больших массивов, что, возможно, означало большую запись.

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

Для меньшего файла (18 мб) он был на 75% быстрее для чтения (1,6 против 6,1 секунды) и на 40% быстрее для записи (2,8 против 4,7 секунды). Он содержал большое количество мелких объектов.

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

Для чтения/записи текста я использовал текстовый файл csv размером 64 МБ. Поток gzip вокруг буферизованного потока был на 11% быстрее для чтения (950 против 1070 миллисекунд) и немного быстрее при записи (7,9 против 8,1 секунды).

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

Ответ 2

GZIPOutputStream уже поставляется со встроенным буфером. Таким образом, нет необходимости вводить BufferedOutputStream прямо рядом с ним в цепочке. gojomo отличный ответ уже дает некоторые рекомендации о том, где разместить буфер.

Размер буфера по умолчанию для GZIPOutputStream составляет всего 512 байт, поэтому вы хотите увеличить его до 8K или даже 64K с помощью параметра конструктора. Размер буфера по умолчанию для BufferedOutputStream составляет 8K, поэтому вы можете измерить преимущество при объединении по умолчанию GZIPOutputStream и BufferedOutputStream. Это преимущество также может быть достигнуто путем правильной калибровки встроенного буфера GZIPOutputStream.

Итак, чтобы ответить на ваш вопрос: "Должен ли я использовать BufferedOutputStream вообще?" → Нет, в вашем случае вы не должны использовать его, но вместо этого установите буфер GZIPOutputStream как минимум на 8K.

Ответ 3

Буферизация помогает, когда конечный пункт назначения данных лучше всего читается/записывается в больших кусках, чем ваш код в противном случае подталкивал бы его. Таким образом, вы, как правило, хотите, чтобы буферизация была как можно ближе к местам, требующим больших кусков. В ваших примерах, что исключенные "..." , так что оберните BufferedOutputStream с помощью GzipOutputStream. И настройте буферный буфер BufferedOutputStream, чтобы он соответствовал тому, что показывает тестирование, лучше всего работает с пунктом назначения.

Я сомневаюсь, что BufferedOutputStream снаружи поможет много, если вообще не будет, без явной буферизации. Почему нет? GzipOutputStream выполнит запись write() s в "..." в блоках одинакового размера независимо от того, присутствует ли внешняя буферизация или нет. Поэтому нет возможности оптимизировать "..." ; вы застряли с размерами GzipOutputStream write() s.

Обратите также внимание на то, что вы используете память более эффективно, буферизируя сжатые данные, а не несжатые данные. Если ваши данные часто имеют сжатие 6X, буфер "внутри" эквивалентен "внешнему" буферу 6X как большой.

Ответ 4

Я предлагаю вам попробовать простой тест времени, сколько времени потребуется, чтобы сжать большой файл и посмотреть, имеет ли это значение. GzipOutputStream имеет буферизацию, но это меньший буфер. Я бы сделал первый с буфером 64 КБ, но вы могли бы найти, что сделать оба лучше.

Ответ 5

Обычно вам нужен буфер, близкий к вашему FileOutputStream (при условии, что что... представляет), чтобы избежать слишком большого количества вызовов в ОС и частого доступа к диску. Однако, если вы пишете много небольших фрагментов в GZIPOutputStream, вам может понадобиться буфер вокруг GZIPOS. Причина заключается в том, что метод записи в GZIPOS синхронизирован, а также приводит к нескольким другим синхронным вызовам и нескольким нативным (JNI) вызовам (для обновления CRC32 и фактического сжатия). Все они добавляют дополнительные накладные расходы для каждого звонка. Поэтому в этом случае я бы сказал, что вы выиграете от обоих буферов.

Ответ 6

Прочитайте javadoc, и вы обнаружите, что BIS используется для буферизации байтов, считанных из некоторого исходного источника. Как только вы получите необработанные байты, которые вы хотите сжать, чтобы вы обернули BIS с помощью ГИС. Нет смысла буферизовать вывод из GZIP, потому что нужно подумать, что насчет буферизации GZIP, кто это сделает?

new GzipInputStream( new BufferedInputStream ( new FileInputXXX