Буферизованный против небуферизованного. Как на самом деле работает буфер? - PullRequest
0 голосов
/ 02 августа 2020

Как на самом деле буфер оптимизирует процесс чтения / записи?

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

введите описание изображения здесь

Ответы [ 3 ]

2 голосов
/ 02 августа 2020

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

File только представление только на пути. Вот из File Javado c:

Абстрактное представление путей к файлам и каталогам.

Между тем, буферизованный поток, например ByteBuffer берет содержимое (зависит от типа буфера, прямой или косвенный ) из файла и выделяет его в память как кучу.

Возвращенные буферы при использовании этого метода затраты на выделение и высвобождение ресурсов обычно несколько выше, чем у непрямых буферов. Содержимое прямых буферов может находиться за пределами обычной кучи со сборкой мусора, поэтому их влияние на объем памяти, занимаемое приложением, может быть неочевидным. Поэтому рекомендуется выделять прямые буферы в первую очередь для больших , долгоживущие буферы, которые являются предметом собственных операций ввода-вывода базовой системы. В общем случае лучше всего выделять прямые буферы только тогда, когда они дают измеримый выигрыш в производительности программы. это более быстрое решение, чем безбуферизованное. Но если файл больше, чем основная память, и к нему обращаются один раз, небуферизация кажется лучшим решением.

2 голосов
/ 06 августа 2020

Фундаментальное заблуждение состоит в том, чтобы предполагать, что файл читается побайтно. Большинство запоминающих устройств, включая жесткие диски и диски с solid состояниями, организуют данные в блоки . Точно так же сетевые протоколы передают данные пакетами , а не отдельными байтами.

Это влияет на работу аппаратного обеспечения контроллера и программного обеспечения нижнего уровня (драйверов и операционной системы). Часто на этом уровне невозможно даже передать один байт. Таким образом, запрос чтения одного байта заканчивается чтением одного блока и игнорированием всего, кроме одного байта. Хуже того, запись одного байта может означать чтение всего блока, изменение одного байта и запись блока обратно в устройство. Для передачи по сети отправка пакета с полезной нагрузкой всего в один байт подразумевает использование 99% полосы пропускания для метаданных, а не фактической полезной нагрузки.

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

Обратите внимание, что даже если базовая система вводит буферизацию в свои или когда оборудование действительно передает отдельные байты, выполнение 100 вызовов операционной системы для передачи одного байта на каждом по-прежнему значительно медленнее, чем выполнение одного вызова операционной системы, сообщающего ему передать 100 байтов за один раз.

Но вы не должны рассматривать буфер как нечто среднее между файлом и вашей программой, как показано на вашем рисунке. Вы должны рассматривать буфер как часть вашей программы. Точно так же, как вы не рассматриваете объект String как нечто среднее между вашей программой и источником символов, а скорее как естественный способ обработки таких элементов. Например, когда вы используете метод массового чтения InputStream (например, FileInputStream) с достаточно большим целевым массивом, нет необходимости оборачивать входной поток в BufferedInputStream; это не улучшит производительность. Вам следует просто держаться подальше от однобайтового метода чтения , насколько это возможно.

В качестве другого практического примера, когда вы используете InputStreamReader, он уже будет считывать байты в буфер (поэтому дополнительных BufferedInputStream не требуется), а внутренний CharsetDecoder будет работать с этим буфером, записывая полученные символы в целевой буфер символов. Когда вы используете, например, Scanner, операции сопоставления с образцом будут работать с этим целевым буфером символов операции декодирования кодировки (когда источником является InputStream или ByteChannel). Затем при доставке результатов совпадения в виде строк они будут созданы другой операцией массового копирования из буфера символов. Так что обработка данных по частям уже является нормой, а не исключением.

Это было включено в дизайн NIO. Таким образом, вместо поддержки однобайтового метода чтения и его исправления путем предоставления декоратора буферизации, как это делает InputStream API, подтипы ByteChannel NIO предлагают только методы, использующие буферы, управляемые приложением .

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

2 голосов
/ 02 августа 2020

В основном для чтения, если вы запрашиваете 1 байт, буфер будет читать 1000 байт и возвращать вам первый байт, для следующих 999 чтений для 1 байта он не будет читать ничего из файла, но будет использовать его внутренний буфер в RAM . Только после того, как вы прочтете все 1000 байтов, он фактически прочитает еще 1000 байтов из фактического файла.

То же самое для записи, но в обратном порядке. Если вы напишете 1 байт, он будет буферизован, и только если вы записали 1000 байтов, они могут быть записаны в файл.

Обратите внимание, что выбор размера буфера немного меняет производительность, см., Например, { ссылка } для получения дополнительных сведений о размере блока файловой системы, доступной оперативной памяти и т. Д. c.

...