У меня есть нетривиальный Bash-скрипт примерно следующего вида:
# Initialization
<generate_data> | while read line; do
# Run tests and filters on line
if [ "$tests_pass" ]; then
echo "$filtered_line"
fi
done | sort <sort_option> | <consume_data>
# Finalization
По сравнению с фильтром генератор потребляет минимальные ресурсы обработки, и, разумеется, операция сортировки не может начаться, пока не будут доступны все отфильтрованные данные. Таким образом, фильтр, представляющий собой каскад из нескольких циклов и условных выражений, изначально написанных в Bash, является узким местом обработки, и единственный процесс, выполняющий этот цикл, потребляет все ядро.
Полезной целью было бы распределить эту логику по нескольким дочерним процессам, каждый из которых запускает отдельные циклы фильтрации и каждый из которых, в свою очередь, потребляет блоки строк из генератора и каждый из которых создает выходные блоки, объединенные в операцию сортировки. Функциональность такого рода доступна с помощью таких инструментов, как GNU Parallel, но для их использования требуется вызов внешней команды для запуска в конвейере.
Доступен ли какой-либо удобный инструмент или функция, позволяющая распределять операции над сценарием между несколькими процессами, не нарушая общей структуры сценария? Я не знаю встроенной функции Bash, но она наверняка была бы полезна.
parallel
, который OP не нужен (хотяinvoking an external command
не так плох, как запуск цикла в bash). @epl Возможно, можно достаточно ускорить ваш фильтр, не прибегая к параллельным вычислениям. С минимальным входом и ожидаемым результатом кто-то может дать вам решение здесь. - person Socowi   schedule 02.12.2019such an improvement applied by itself is far inferior to that from utilizing more hardware in parallel
Я бы на это не рассчитывал. Циклы в bash настолько медленные, что даже в параллельном режиме они часто не могут обогнать другие языки или даже специализированные инструменты. Пример. Чтобы сгенерировать числа от 1 до 4 000 000, я сравнил следующие подходы на четырехъядерный. Один цикл bash (16,1 с); четыре петли баш параллельно (5,2с); один awk-цикл (0,9 с); иseq
(0,1 с). Обратите внимание, что здесь используются только встроенные циклы. Если вы неоднократно вызываете внешние программы, это еще хуже. - person Socowi   schedule 02.12.2019LPUSH
добавить строки/блоки в список Redis и запустить несколько процессоров, которыеBRPOP
блокируют список, аLPUSH
приводят к другому списку. Задания процессора могут выполняться наbash
, Python или C++ на всех компьютерах в вашей сети. - person Mark Setchell   schedule 05.12.2019&
и ждете$!
? Я обычно сохраняю каждый результат в массиве, жду завершения всех PID, а затем запускаю процесс сортировки/окончания. Я напишу ответ с коротким примером позже сегодня, если хотите. - person Matthieu   schedule 07.12.2019