Верстакфорум практиков
рекламаiprazon: приватные серверные адреса IPv4 и SOCKS5, безлимитный трафик, бесплатный тест до 2 часов
ФорумСкрипты и автоматизация

Параллельный запуск через xargs без лишних зависимостей

linuxvsem
linuxvsem
Участник
сообщений 830
с июл
15 июля, 14:42первое сообщение

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

Базовое вроде работает:

xargs -a spisok.txt -P 8 -n 1 -I{} sh -c './obrabotat.sh {}'

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

ferrum
ferrum
Участник
сообщений 660
с сен
22 декабря, 17:59#2

Первым делом уберите -I. Он молча ставит -n 1, в части сборок сводит параллель на нет, и вдобавок ломает кавычки внутри строки: имя с апострофом развалит вам команду.

Форма без подстановки:

xargs -a spisok.txt -P 8 -n 1 sh -c 'obrabotat "$1"' _

Подчёркивание в хвосте это имя нулевого аргумента. Забудете его, и первый элемент списка уедет в имя команды и потеряется молча.

Данила Р
Данила Р
Новичок
сообщений 145
с мар, второй сезон
1 мая, 08:16#3

а пробелы в именах чем лечить?

kvadrat_ru
kvadrat_ru
Участник
сообщений 855
с июл
8 октября, 11:33#4

Нулевым разделителем. Список готовите через find -print0 или printf с \0, читаете с флагом -0. Пробелы, переводы строк и кавычки в именах после этого перестают что-либо значить.

find vygruzki -name '*.csv' -print0 | xargs -0 -P 6 -n 1 sh -c 'szhat "$1"' _
linuxvsem
linuxvsem
Участник
сообщений 830
с июл
15 марта, 14:50#5
ferrum: он молча ставит -n 1

Проверил на своей сборке: с -I параллель отработала, но втрое медленнее. Убрал, пошло ровно.

Осталось главное. Как узнать, что именно упало? xargs возвращает 123, если хоть один вызов дал ненулевой код, и на этом вся его щедрость заканчивается.

Наиль Габдуллин
Наиль Габдуллин
Знаток
сообщений 1885
с мар
22 августа, 17:07#6

Собирать результат должен сам обработчик, xargs для этого слишком туп.

Заводите на каждую задачу отдельный файл с выводом плюс одну строку в общий журнал. Тогда разбор после прогона превращается в обычный grep.

#!/bin/sh
# obrabotat: одна задача, свой файл с выводом
zadacha="$1"
imya=$(printf '%s' "$zadacha" | md5sum | cut -c1-12)
if vypolnit "$zadacha" > "rez/$imya.out" 2> "rez/$imya.err"; then
  echo "ok $zadacha" >> rez/itog.log
else
  echo "fail $? $zadacha" >> rez/itog.log
fi

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

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

И про число процессов. Флаг -P 0 запускает столько, сколько строк в списке, это верный способ уронить машину вместе с сетью. Ставьте руками: для сетевых задач ориентир от восьми до тридцати, для тяжёлых по процессору по числу ядер.

время прогона списка на 5000 строк, минуты
время прогона списка на 5000 строк, минуты
разбираю чужие конфиги за печенье
kvadrat_ru
kvadrat_ru
Участник
сообщений 855
с июл
1 января, 08:24#7

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

Наиль Габдуллин
Наиль Габдуллин
Знаток
сообщений 1885
с мар
8 июня, 11:41#8

Каталог под каждый запуск обязательно. Иначе повторный прогон затрёт файлы прошлого и сравнивать станет нечего.

разбираю чужие конфиги за печенье
ferrum
ferrum
Участник
сообщений 660
с сен
15 ноября, 14:58#9

Ещё мелочь: -P без -n или -L собирает в одну команду сколько влезет, и параллель получается бумажная. Ставьте оба флага всегда.

linuxvsem
linuxvsem
Участник
сообщений 830
с июл
22 апреля, 17:15#10

Собрал по советам: -0 на входе, -P 12 -n 1, обработчик пишет свой файл и строку в общий журнал, каталог результатов по времени запуска.

Список на пять тысяч строк раньше шёл пятьдесят четыре минуты, теперь девять. Упавшие видны одним grep по журналу, за прогон их вышло семнадцать, все по таймауту.

Спасибо, parallel так и не понадобился.