Назад | Перейти на главную страницу

Буферизируется ли обработка больших файлов через каналы bash?

Мне нужно использовать следующую команду:

$ cat large.input.file | process.py > large.output.file

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

Есть ли способ указать bash использовать большой буфер памяти при работе с таким каналом?

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

Вы можете заменить cat в вашем примере с просмотрщик труб (pv) (доступно в большинстве стандартных репозиториев и легко выполняется, если его нет в репозитории вашего дистрибутива), что позволяет вам установить его для буферизации большего количества (с -B/--buffer-bytes варианты) и отображает индикатор выполнения (если вы не попросите этого не делать), что может быть очень удобно при длительной работе, если ваш process.py не выводит собственную информацию о прогрессе. Для передачи данных из одного места на диске в другое место на том же диске это может иметь большое значение, если только весь процесс в основном не связан с ЦП, а не с вводом-выводом.

Итак, для буфера 1 МБ вы можете сделать:

pv -B 1m large.input.file | process.py > large.output.file

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

Другой вариант - использовать более «стандартный» (стандартный с точки зрения общедоступности по умолчанию, его формат командной строки немного отличается от большинства распространенных команд) dd, хотя здесь нет индикатора выполнения:

dd if=large.input.file bs=1048576 | process.py > large.output.file

Изменить: ps. подвески могут указывать на то, что cat не требуется в вашем примере, так как следующее будет работать так же хорошо и будет немного более эффективным:

process.py < large.input.file > large.output.file

Некоторые люди ссылаются на удаление необоснованных звонков cat как "демогификацию" этих людей, наверное, не стоит поощрять ...

Нет ли старого инструмента unix под названием «буфер»? Не то чтобы это было необходимо с сегодняшними методами кэширования - но оно есть.

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

При этом: если вы можете изменить process.py, вы можете реализовать свою собственную буферизацию. Если вы не можете изменить process.py, вы можете написать свой собственный buffer.py и использовать его так.

$ cat large.input.file | buffer.py | process.py | buffer.py > large.output.file

Наверное, гораздо проще было бы читать и писать с RAM-диск.

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

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

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

Использование программы-буфера в качестве замены команды cat может привести к определенным улучшениям ... в зависимости от ситуации.

Наслаждайтесь!

Попробуйте использовать эту небольшую программу Python 2, которую я только что собрал:

#! /usr/bin/python2
# This executable path is Gentoo-specific, you might need to change it yourself

import sys;

if sys.argv[1].endswith('K'):
   bytestoread = int(sys.argv[1].translate(None, 'K')) * 1024;
elif sys.argv[1].endswith('M'):
   bytestoread = int(sys.argv[1].translate(None, 'M')) * 1024 * 1024;
elif sys.argv[1].endswith('G'):
   bytestoread = int(sys.argv[1].translate(None, 'G')) * 1024 * 1024 * 1024;

while True:
   buffer = sys.stdin.read(bytestoread);
   if buffer == '':
      exit();
   sys.stdout.write(buffer);
   buffer = None;   # This one is for making sure the read buffer will get destroyed, otherwise we could bring our system to a halt if we have 8 GB of RAM, request a 5 GB buffer, and it ends up eating 10 GB of memory.

Чтобы использовать этот файл, назовите его так:

cat large.input.file | process.py | buffer.py 2G > large.output.file

Вы можете использовать 2K, чтобы указать 2 килобайта, 2M для 2 мегабайт, 2G для 2 гигабайт, если хотите, вы можете добавить 2T для 2 терабайт буфера: 3

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

Он будет буферизоваться разумно, но нет хорошего способа настроить его размер.

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

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

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

Если вы можете изменить process.py, вы могли бы вместо чтения / записи с помощью каналов читать / писать напрямую и использовать вместо этого буферизацию и / или memmap'ed файлы, которые помогли бы снять часть нагрузки с системы.