2010-12-14 3 views
5

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

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

я имел следующий код, чтобы создать свой 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? Это определенно не нужно, но размер файла значительно уменьшается при его использовании.

ответ

8

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

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

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

+0

Я предлагаю вам попробовать буфер 64K для GZIPInputStream при чтении с диска. Я использую 1 МБ, что, вероятно, будет более чем необходимо. ;) –

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

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

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

    Существует мало смысла положить BufferedInputStream внутри GZIPInputStream, поскольку последний уже буфера своего вклада

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

+0

Спасибо за понимание. – Brad

+0

Добро пожаловать. Я отредактировал ответ немного подробнее. – NPE

Смежные вопросы