Определение подходящего размера буфера

Я использую ByteBuffer.allocateDirect (), чтобы выделить некоторую буферную память для чтения файла в память, а затем, в конечном итоге, хэшировать байты этих файлов и получить из него хэш файла (SHA). Размер входных файлов очень велик - от нескольких КБ до нескольких ГБ.

Я прочитал несколько потоков и страниц (даже некоторые о SO) относительно выбора размера буфера. Некоторые советовали попытаться выбрать тот, который использует собственная файловая система, чтобы минимизировать вероятность операции чтения для частичного блока и т. Д. Например, буфер размером 4100 байт, а NTFS по умолчанию - 4096, поэтому дополнительные 4 бита потребуют отдельной операции чтения, что является чрезвычайно расточительным.

Итак, придерживаясь степеней 2, 1024, 2048, 4096, 8192 и т. Д. Я видел, как некоторые рекомендуют буферы размером 32 КБ, а другие рекомендуют делать буфер размером с входной файл (возможно, подходит для небольших файлов, но что насчет больших файлов?).

Насколько важно придерживаться собственных буферов размера блока? Говоря современным языком (при условии, что современный диск SATA или лучше с как минимум 8 МБ кеш-памяти на диске и другая современная «магия» ОС для оптимизации ввода-вывода), насколько критичным является размер буфера и как мне лучше всего определить, какой размер установить для моего? Могу я его статически установить или определить динамически? Спасибо за понимание.


person SnakeDoc    schedule 17.04.2013    source источник
comment
Единственный способ узнать это - проверить. Учтите, что то, что лучше всего подходит для одного компьютера, может не применяться к другому. Создайте или загрузите файлы разного размера и прочтите их. Посмотрите, сколько времени это займет.   -  person Lee Meador    schedule 17.04.2013
comment
Возможный дубликат stackoverflow.com/questions/236861/   -  person Ben Barkay    schedule 17.04.2013
comment
@LeeMeador проблема с тестированием заключается в том, что размер входного файла полностью неизвестен.   -  person SnakeDoc    schedule 17.04.2013
comment
Просто используйте репрезентативные файлы различных размеров в ожидаемом диапазоне и усредняйте количество байтов в секунду для нескольких файлов. Например, 3–300 МБ может быть интересным диапазоном. Или от 100К до 10 Гб. Ваше предположение будет достаточно хорошим для оценки.   -  person Lee Meador    schedule 17.04.2013


Ответы (1)


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

Как вы говорите, если вы выделяете 4100, а фактический размер блока равен 4096, вам потребуется два чтения для заполнения буфера. Если вместо этого у вас есть буфер размером 1 000 000 байт, то верхний или нижний уровень на один блок не имеет значения (поскольку для заполнения этого буфера требуется 245 блоков размером 4096 байт). Более того, больший буфер означает, что ОС имеет больше шансов упорядочить чтение.

Тем не менее, я бы не стал использовать для этого NIO. Вместо этого я бы использовал простой BufferedInputStream, возможно, с буфером 1k для моих read()s.

Основное преимущество NIO - хранить данные вне кучи Java. Если вы читаете и записываете файл, например, использование InputStream означает, что ОС считывает данные в буфер, управляемый JVM, JVM копирует их в буфер в куче, а затем снова копирует в не-кучу. buffer, затем ОС считывает этот буфер вне кучи для записи фактических блоков диска (и обычно добавляет свои собственные буферы). В этом случае NIO удалит копии из собственной кучи.

Однако для вычисления хэша вам нужны данные в куче Java и Mac SPI переместит его туда. Таким образом, вы не получаете выгоды от того, что NBI хранит данные вне кучи, а ИМО легче написать «старый ввод-вывод».

Только не забывайте, что InputStream.read() не гарантированно прочитает все запрошенные вами байты.

person parsifal    schedule 17.04.2013
comment
хм ... я просто потратил некоторое время на рефакторинг моего метода / алгоритма хеширования для повышения производительности. См. Эту ветку: stackoverflow.com/questions/16050827/ - прокрутите вниз до моего последнего обновления, чтобы увидеть мой текущий метод - первый метод в OP был моим исходным методом, который работал очень хорошо, но я решил оптимизировать / микрооптимизировать его, так как хеширование очень неотъемлемая часть проекта, над которым я работаю. - person SnakeDoc; 17.04.2013
comment
@SnakeDoc - Глядя на ваш другой вопрос, я вижу, что вы увеличили размер буфера до 8K. Интересно, как бы изменилась производительность в первой (InputStream) версии, если бы вы использовали буфер аналогичного размера? - person parsifal; 18.04.2013
comment
Но, учитывая, что ваш код ByteBuffer выглядит разумным, я бы обратился к идее гораздо большего размера буфера, чтобы операционная система могла выполнять большое последовательное чтение. Я не уверен, что вы получите от этого огромный прирост производительности, но, как сказали некоторые комментаторы, вы узнаете об этом только при повторном тестировании. - person parsifal; 18.04.2013
comment
спасибо за ввод - я, честно говоря, никогда не возвращался и не пробовал разные размеры буфера в моем исходном алгоритме InputStream ... так как мне сообщили, что java.nio.* был подходящим вариантом для любых ориентированных на производительность операций ввода-вывода, которые мне нужно было сделать. .. даже если это просто для чтения ... хм ... Мне нужно будет протестировать это и попытаться опубликовать ответ для полноты картины. Мое самое сложное препятствие - как правильно протестировать эти вещи без той магии, которую операционная система и дисковые накопители делают для оптимизации ввода-вывода, искажающей мои результаты ... - person SnakeDoc; 18.04.2013
comment
@SnakeDoc - Я не уверен, что вы должны пытаться изолировать ОС и дисковые накопители, потому что они повлияют на время вашего производства. Если вы можете, попробуйте воспроизвести свою производственную среду в тесте (IMO, правильная ОС и размер памяти будут самыми важными факторами, меньше типа диска, если вы не сравниваете SAN и SSD). Для тестирования попробуйте запустить одну и ту же программу несколько раз, а также попробуйте чередовать свои программы. - person parsifal; 18.04.2013
comment
Наконец, решите, имеет ли значение буферный кеш. Если вы постоянно обрабатываете новые файлы в производственной среде, то кеш будет выполнять повторные тестовые прогоны быстрее, чем они есть на самом деле. Вот страница, на которой перечислены некоторые способы очистки кеша (я не могу вспомнить, используете ли вы Linux или Windows, но я использую Linux, поэтому я ищу именно это): commandlinefu.com/commands/view/1026/ - person parsifal; 18.04.2013
comment
Это Linux FTW, детка! ;-p А если серьезно, то спасибо parsifal за совет. То, что вы говорите, имеет большой смысл. Я ожидаю, что для большинства запусков программы почти не будет магии OS / Disk, поскольку она разработана как ночная работа, и набор файлов будет кардинально меняться в течение дня. Я собираюсь собрать тестовую установку, чтобы попробовать несколько размеров кеша для обоих алгоритмов и для файлов разных размеров и посмотреть, смогу ли я получить какие-нибудь приличные тесты наполовину. Я опубликую здесь свой код test = rig, как только он будет готов, чтобы другие могли легко запустить свой собственный тест. Еще раз спасибо! - person SnakeDoc; 18.04.2013