Поиск оптимального размера для BufferedInputStream в Java - PullRequest
5 голосов
/ 14 декабря 2010

Я профилировал свой код, который загружал двоичный файл. Время загрузки составляло около 15 секунд.

Большая часть моего времени загрузки приходилась на методы, которые загружали двоичные данные.

У меня был следующий код для создания моего DataInputStream:

is = new DataInputStream(
     new GZIPInputStream(
     new FileInputStream("file.bin")));

И я изменил это на:

is = new DataInputStream(
     new BufferedInputStream(
     new GZIPInputStream(
     new FileInputStream("file.bin"))));

Итак, после того, как я сделал это небольшое изменение, код загрузки изменился с 15 секунд до 4.

Но потом я обнаружил, что BufferedInputStream имеет два конструктора. Другой конструктор позволяет вам явно определить размер буфера.

У меня два вопроса:

  1. Какой размер выбран в BufferedInputStream и является ли он идеальным? Если нет, как я могу найти оптимальный размер для буфера? Должен ли я написать небольшой кусочек кода, который выполняет бинарный поиск?
  2. Это лучший способ использовать BufferedInputStream? Первоначально я имел это в GZIPInputStream, но была незначительная выгода. Я предполагаю, что код делает сейчас каждый раз, когда необходимо заполнить файловый буфер, входной поток GZIP проходит и декодирует x байтов (где x - размер буфера) Стоит ли просто опустить GZIPInputStream полностью? Это определенно не нужно, но размер моего файла резко уменьшается при его использовании.

Ответы [ 2 ]

8 голосов
/ 14 декабря 2010

И GZIPInputStream, и BufferedInputStream используют внутренний буфер. Вот почему использование BufferedInputStream внутри GZIPInputStream не дает никаких преимуществ. Проблема с GZIPInputStream состоит в том, что он не буферизует вывод, который он генерирует, поэтому ваша текущая версия намного быстрее.

Размер буфера по умолчанию для BufferedInputStream составляет 8 КБ, поэтому вы можете попробовать увеличить или уменьшить его, чтобы посмотреть, поможет ли это. Я сомневаюсь, что точное число имеет большое значение, поэтому вы можете просто умножить или разделить на два.

Если файл небольшой, вы также можете попытаться полностью его буферизовать. Это должно дать вам лучшую производительность в теории. Вы также можете попытаться увеличить размер буфера GZIPInputStream (по умолчанию 512 байт), так как это может ускорить чтение с диска.

4 голосов
/ 14 декабря 2010
  1. Не беспокойтесь о бинарном поиске.Просто попробуйте несколько значений вручную и сравните время (вы можете выполнить ручной двоичный поиск, если хотите).Скорее всего, вы обнаружите, что очень широкий диапазон размеров буфера даст вам производительность, близкую к оптимальной, поэтому выберите наименьшее, что подходит.

  2. Что у вас есть, так этоправильный порядок:

    is = new DataInputStream(
         new BufferedInputStream(
         new GZIPInputStream(
         new FileInputStream("file.bin"))));
    

    Не имеет смысла помещать BufferedInputStream внутри GZIPInputStream, так как последний уже буферизует свой вход (но не вывод.)* может быть выигрышным, но, скорее всего, это пагубно сказывается на производительности, если данные должны быть прочитаны с диска и не находятся в кэше файловой системы.Причина в том, что чтение с диска очень медленное, а распаковка gzip очень быстрая.Поэтому обычно дешевле читать меньше данных с диска и распаковывать их в памяти, чем читать больше данных с диска.

...