
У меня есть большое количество больших файлов (сотни файлов, сотни МБ каждый), которые мне нужно пропустить через ряд программ для их фильтрации и преобразования. Я использую преимущества нескольких ядер ЦП, поэтому я запускаю несколько экземпляров одного и того же канала для каждого файла (может быть до сотни ядер, и могу использовать ssh как часть канала, если это имеет какое-либо значение для ответа). Я хочу контролировать каждый канал, и я использую pv
для этого. Вот минимальный пример того, что у меня есть:
$ pv file-001.gz | gunzip | xz > file-001.xz
1.58GB 0:00:02 [ 713MB/s] [=================================>] 100%
На самом деле я делаю в канале еще несколько вещей, включая передачу данных на другие машины по ssh и их прохождение через фильтры на этих машинах, но канал всегда заканчивается перенаправлением в новый файл на главном хосте. Кроме того, ни один этап в канале не требует всего набора данных; они могут работать построчно или по частям.
В настоящее время мне нужно отдельное окно терминала для каждого экземпляра конвейера. Я хотел бы запустить n параллельных экземпляров конвейера в одном терминале/оболочке и получить вывод от каждого экземпляра pv на его собственной строке. Что-то вроде этого:
1.48GB 0:00:54 [ 704MB/s] [===============================> ] 97% ETA 00:00:06
1.58GB 0:01:00 [ 713MB/s] [=================================>] 100%
0.75GB 0:00:31 [ 709MB/s] [================> ] 50% ETA 00:00:29
Значение n будет числом строк, которые я могу поместить в окне терминала, скажем, 3-50 или около того. Точный формат отчета о ходе выполнения не важен, если он включает скорость, процент выполнения, прошедшее время и предполагаемое оставшееся время. Также не важно, что я использую pv
, можно использовать какую-то другую программу, если я могу легко ее установить или просто оболочку (предпочтительно bash). Однако важно то, что метод может обрабатывать случайные поломки конвейера в случае, если часть конвейера по какой-то причине выходит из строя. Я также хотел бы начинать новые задания каждый раз, когда задание завершается (успешно или нет), и все еще остаются необработанные файлы.
Есть идеи, как это сделать?
Обратите внимание, что я уже пробовалGNU-параллельный, но его функции ssh, по-видимому, предполагают, что каждый входной файл сначала передается на удаленный хост, затем обрабатывается, а затем результат передается обратно, чего я хочу избежать из-за объема вовлеченных данных и ограниченного объема пространства на каждом узле обработки.
решение1
Есть идеи, как это сделать?
Нет.
pv имеет опции -c и -N, которые позволят вам делать то, что вы хотите
$ pv -cN source access.log | gzip | pv -cN gzip > access.log.gz
source: 760MB 0:00:15 [37.4MB/s] [=> ] 19% ETA 0:01:02
gzip: 34.5MB 0:00:15 [1.74MB/s] [ <=> ]
но я не вижу, как применить эту функцию к нескольким конвейерам
Однако, если вы посмотрите на страницу руководства pv, вы увидите следующее:
(tar cf - . \
| pv -n -s $(du -sb . | awk '{print $1}') \
| gzip -9 > out.tgz) 2>&1 \
| dialog --gauge 'Progress' 7 70
Таким образом, вы можете расширить это для запуска нескольких задач параллельно, пока это приемлемо для просмотра прогресса в кластере небольших окон. Я бы попробовал Xdialog.
В настоящее время мне нужно отдельное окно терминала для каждого экземпляра трубы.
Моя главная мысль заключается в том, что вам не обязательно интерактивно открывать множество окон терминала, вы можете сделать так, чтобы один скрипт сам открывал множество диалоговых окон.
решение2
Вы искали --pipe
GNU Parallel?
cat bigfiles* | pv | parallel --pipe -S server1,server2 'cat | process_pipe'
(кот включен для выразительности)
По умолчанию размер блока составляет 1 МБ, его можно изменить с помощью --block.
-- редактировать для личной переписки --
На основании вышеизложенного можно получить 1-1 переписку следующим образом:
parallel --eta "cat {} | parallel --pipe -S server1,server2 'cat | process_pipe' > {}.out" ::: bigfiles*
(кот включен для выразительности)
Это не совсем оптимально, так как внутренний параллелизм не будет знать о своих братьях и сестрах и, таким образом, может порождать больше на server1, чем на server2. Один из способов избежать этого - -j1 на внешнем параллелизме, но это не будет оптимальным, если внутренний имеет достаточно блоков только для первого сервера. Другими словами: чтобы идеально сбалансировать вашу рабочую нагрузку, вам, возможно, придется немного повозиться с этим - возможно, даже использовать --load 100% или что-то подобное.
--- правка: Борьба со сбоями ---
Если process_pipe
возвращается ошибка, то следует повторить команду еще 2 раза:
parallel --retries 3 --eta "cat {} | parallel --pipe -S server1,server2 'cat | process_pipe' > {}.out" ::: bigfiles*