Параллельный запуск через xargs без лишних зависимостей
linuxvsem
Участник
сообщений 830 с июл
15 июля, 14:42первое сообщение
Разгоняю обход списка. GNU parallel на своих машинах есть, на арендованных ставить не дают, поэтому смотрю в сторону xargs: он лежит везде и с ним ничего просить не надо.
Базовое вроде работает:
xargs -a spisok.txt -P 8 -n 1 -I{} sh -c './obrabotat.sh {}'
Дальше начинаются вопросы. Вывод перемешивается в кашу, коды возврата теряются, на именах с пробелами всё разъезжается. Кто как это причёсывал?
Первым делом уберите -I. Он молча ставит -n 1, в части сборок сводит параллель на нет, и вдобавок ломает кавычки внутри строки: имя с апострофом развалит вам команду.
Форма без подстановки:
xargs -a spisok.txt -P 8 -n 1 sh -c 'obrabotat "$1"' _
Подчёркивание в хвосте это имя нулевого аргумента. Забудете его, и первый элемент списка уедет в имя команды и потеряется молча.
Нулевым разделителем. Список готовите через find -print0 или printf с \0, читаете с флагом -0. Пробелы, переводы строк и кавычки в именах после этого перестают что-либо значить.
Проверил на своей сборке: с -I параллель отработала, но втрое медленнее. Убрал, пошло ровно.
Осталось главное. Как узнать, что именно упало? xargs возвращает 123, если хоть один вызов дал ненулевой код, и на этом вся его щедрость заканчивается.
Собирать результат должен сам обработчик, 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 запускает столько, сколько строк в списке, это верный способ уронить машину вместе с сетью. Ставьте руками: для сетевых задач ориентир от восьми до тридцати, для тяжёлых по процессору по числу ядер.
Собрал по советам: -0 на входе, -P 12 -n 1, обработчик пишет свой файл и строку в общий журнал, каталог результатов по времени запуска.
Список на пять тысяч строк раньше шёл пятьдесят четыре минуты, теперь девять. Упавшие видны одним grep по журналу, за прогон их вышло семнадцать, все по таймауту.
Спасибо, parallel так и не понадобился.
✉
Регистрация временно закрыта
Набор новых участников приостановлен, пока разбираем очередь заявок. Открывать будем частями, чтобы модераторы успевали.
Чтение форума открыто целиком: все разделы, все темы, поиск по заголовкам. Ничего вводить не нужно.