Значение аргумента x может меняться в диапазоне от 1 до 30 000. Выполнение команды для одного аргумента занимает от 30 секунд до 15 минут. Нужно максимально быстро выполнить эту команду для заданного диапазона аргументов на N-ядерном сервере максимально используя ресурсы сервера.
Возможные варианты решения
- Простой цикл от 1 до 30 тысяч с запуском команды на каждой итерации будет использовать только 1 ядро. Это решение неприемлемо: оно будет работать слишком долго и не задействует все доступные ресурсы сервера.
- Можно вручную разбить диапазон на N частей и запустить N циклов вида:
for i in `seq 1 1000` do ./do-something.sh -x $i done
Второе решение лучше первого — оно задействует все доступные ядра процессора, но оно все равно неприемлемо. Команды выполняются с непостоянной скоростью. В каком-то из диапазонов могут попасться только легкие команды, которые выполнятся, предположим, за несколько минут, а в каком-то — тяжелые и их выполнение затянется на несколько часов. Таким образом, часть ядер быстро освободится, будет простаивать и ресурсы сервера опять будут использованы неоптимально.
Как запускать программы Linux в Windows при помощи Bash эмулятора
Решение с xargs
Утилита xargs , входящая во все современные дистрибутивы Linux, позволяет выполнить заданную команду для списка аргументов поступивших на стандартный ввод. Полезные ссылки:
- http://offbytwo.com/2011/06/26/things-you-didnt-know-about-xargs.html
- http://habrahabr.ru/company/selectel/blog/248207/
В следующем примере берется список файлов текущей директории ls (в примере использован корень проекта на фреймворке Yii2, ничего секретного) и для каждого файла в директории применяется команда file , определяющая тип файла:
ls | xargs file assets: directory commands: directory composer.json: ASCII text composer.lock: UTF-8 Unicode text config: directory controllers: directory mail: directory migrations: directory models: directory modules: directory requirements.php: PHP script, ASCII text runtime: directory tests: directory vendor: directory views: directory web: directory yii: a /usr/bin/env php script, ASCII text executable yii.bat: DOS batch file, ASCII text
Аргумент -P позволяет задать сколько параллельных потоков будет использовано для выполнения задачи.
Поэкспериментируем. Возьмем следующий скрипт и назовем его do-something.sh :
#!/usr/bin/env bash # Check for command line arguments if [ $# -lt 1 ] then echo «No options found!» exit 1 fi # Get number while getopts «x:» opt do case $opt in x) num=$OPTARG ;; *) echo «No reasonable options found!»;; esac done rnd=$(shuf -i 1-100 -n 1) rnd=$(echo «$rnd 100″ | awk ») sleep $rnd echo $num
Этот скрипт берет на вход число и выводит его на экран с задержкой от 0 до 1 секунды. Теперь запустим этот скрипт командой time echo | xargs -n 1 ./do-something.sh -x . Эта команда выполняет следующие задачи:
- генерирует последовательность чисел от 1 до 10: echo ,
- передает эти числа по одному в наш скрипт (за это отвечает аргумент -n 1 , без него вся последовательность будет воспринята как один длинный аргумент, так как значения разделены пробелом, а не переводом строки),
- в конце работы скрипта командой time выводит затраченное время.
В результате мы получим примерно такой вывод:
Как запускать несколько ОС на одном компьютере? Виртуальная машина VirtualBox. Запуск Linux в 10.
time echo | xargs -n 1 ./do-something.sh -x 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 real 0m10.301s user 0m0.042s sys 0m0.194s
А теперь запустим ту же команду с опцией -P 4 , что заставит скрипт выполняться в 4 потока:
time echo | xargs -n 1 -P 4 ./do-something.sh -x 4 2 6 1 3 8 10 5 12 9 7 11 13 15 14 19 16 17 20 18 real 0m2.651s user 0m0.032s sys 0m0.215s
В этом примере мы видим, что команды выполнились в 4 раза быстрее, так как запускались параллельно. То что на результат практически не влияет генератор случайных чисел легко убедиться заменив случайную паузу константой.
Теоретически, можно для числа потоков задать значение превышающее число доступных ядер на компьютере. В зависимости от выполняемой программы это может привести как к повышению, так и к понижению скорости выполнения, поэтому оптимальное значение числа потоков должно быть выбрано индивидуально для каждого конкретного приложения.
У xargs есть один недостаток. Давайте заменим в скрипте do-something.sh sleep $rnd на sleep 0.1 . Это сделает задержку не случайной, а постоянной. Теперь еще раз выполним time echo | xargs -n 1 -P 4 ./do-something.sh -x :
time echo | xargs -n 1 -P 4 ./do-something.sh -x 1 3 2 4 5 6 7 8 9 10 12 11 13 14 15 16 17 18 19 20 real 0m0.560s user 0m0.034s sys 0m0.186s
Видно, что результаты выводятся не последовательно, это не всегда приемлемо.
Решение с GNU Parallel
Ниже перевод введения из мануала к утилите:
GNU Parallel — утилита командной строки для параллельного запуска задач на одном или нескольких компьютерах. Задача в данном контексте — это одна команда или скрипт, который должен быть запущен для каждого входящего аргумента. Типичный набор аргументов — это список файлов, хостов, пользователей, урлов или таблиц. Аргументы также могут быть переданы через пайп. GNU parallel может разделить аргументы и параллельно передать их командам.
Если вы используете xargs, то вы легко сможете использовать parallel, так как эта утилита поддерживает те же аргументы командной строки что и xargs. Если вы используете циклы в шелл-скриптах, то, вероятно, parallel поможет вам избавиться от них и ускорить выполнение за счет параллельного запуска команд.
GNU parallel возаращает результаты выполнения команд в том же порядке как если бы они были запущены последовательно. Это делает возможным использование результатов работы parallel как входных данных для других программ.
Для каждой входящей строки GNU parallel запустит команду и передаст ей эту строку в качетсве аргументов. Если команда не задана, то входящая строка будет исполнена. Несколько строк будут выполнены одновременно. GNU parallel может быть использована как замена для xargs и cat | bash.
У этой утилиты как минмум 2 видимых преимущества перед xargs:
- она позволяет запускать команды не в рамках одного сервера, а сразу на нескольких,
- руководство обещает, что результаты будут выводиться последовательно.
Испытаем. Поверим обещаниям того, что parallel принимает те же аргументы, что и xargs и просто заменим имя одной утилиты на другую в команде, которую использовали ранее:
time echo | parallel -n 1 -P 4 ./do-something.sh -x 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 real 0m0.562s user 0m0.135s sys 0m0.096s
Работает! Команда выполнилась примено за те же 0,5 секунд, что и xargs и результат возвращен в правильной последовательности.
Теперь попробуем вернуть обратно случайную задержку, зменим в скрипте do-something.sh sleep 0.1 на sleep $rnd и запустим еще раз. Результат будет возвращен опять в правильной последовательности, несмотря на то, что из-за разной задержки команды запущенные позже могут быть выполнены раньше предыдущих команд (это хорошо видно во втором результате выше).
Единственным недостатком является то, что xargs возвращает результаты как только они готовы, а parallel — только тогда когда выполнение всех команд завершено. Но это цена, которую приходится платить за корректную последовательность результатов. Если запустить parallel с аргументом —bar , то во время работы будет выводиться прогресс бар, показывающий процент выполненных команд.
Теперь испытаем еще одну киллер-фичу parallel — возможность запустить команду на нескольких серверах сразу. Для этого воспользуемся примером из доки: https://www.gnu.org/software/parallel/man.html#EXAMPLE:-Parallel-grep.
# Добавим список серверов в конфиг. В моем случае сервера имеют имена dev и test (echo dev; echo test) > .parallel/my_cluster # Убедимся, что существует файл .ssh/config и забэкапим его touch .ssh/config cp .ssh/config .ssh/config.backup # Временно отключим StrictHostKeyChecking (echo ‘Host *’; echo StrictHostKeyChecking no) >> .ssh/config parallel —slf my_cluster —nonall true # Откатываем назад изменения StrictHostKeyChecking в конфиге SSH mv .ssh/config.backup .ssh/config
Теперь сервера из файла .parallel/my_cluster добавлены в .ssh/known_hosts .
Наконец, нужно скопировать скрипт do-something.sh в домашнюю директорию текущего пользователя на удаленных серверах (в моем примере test и dev).
После выполненной подготовки мы можем запустить команду на серверах dev и test добавив к вызову parallel опцию —sshlogin dev,test .
time echo | parallel -n 1 -P 4 —sshlogin test,dev ./do-something.sh -x real 0m0.334s user 0m0.080s sys 0m0.032s
Виден выигрыш в скорости даже на такой элементарной операции, несмотря на оверхед связанный с установкой соединения по сети. В случае с действительно тяжелыми командами, выполнение которых может занимать десятки секунд или минут, выигрыш от такого распределенного выполнения может оказаться еще заметнее.
Источник: romka.eu
Как выполнить несколько команд одновременно в системах Linux
Как администратор Linux, вы можете знать, насколько полезной может быть командная строка для выполнения различных действий, таких как установка приложения, установка системного патча и перезапуск службы.
Выполнение двух или более команд одновременно является еще более эффективным и экономит время.
В этом руководстве мы рассмотрим различные способы объединения и эффективного выполнения нескольких команд Linux.
Semicolon (;) | command 1; command2 | Выполняет сначала команду 1, а затем команду 2 |
AND () | command 1 command2 | Выполнение команды 2 только при успешном выполнении команды 1 |
OR (||) | command 1 || command2 | Выполнение команды 2 только в случае неудачи команды 1 |
1) Объединение команд с помощью оператора “точка с запятой” (;)
Если вы хотите выполнить все команды независимо от того, не выполнились ли предыдущие, разделите их точкой с запятой.
В этом случае все команды выполняются одна за другой.
command 1; command 2; … command N
Например: Просто введите следующие три команды в одной строке, разделенные точкой с запятой.
Система покажет вам имя пользователя (whoami), проверит, в каком каталоге вы сейчас находитесь (pwd), и как долго работает система (uptime).
Как я уже сказал, если в цепочке команд произойдет сбой одной команды, остальные команды всегда будут выполняться, как показано ниже.
2) Запуск двух или более команд одновременно в Linux с помощью оператора логического AND ()
Если вы хотите, чтобы каждая команда выполнялась только после успешного выполнения предыдущей команды, объедините их с помощью оператора ‘’.
command 1 command 2 … command N
Например: Введите следующие две команды в одной строке, разделенные двумя амперсандами ( ).
Система создаст каталог под названием ‘MyDirectory’, а затем перейдет в этот каталог.
mkdir MyDirectory cd MyDirectory
Повторное выполнение вышеуказанной команды не даст результата, поскольку ‘MyDirectory’ уже существует.
Поэтому ‘команда 1’ возвращает ошибку.
Оператор ‘AND’ выполнит ‘команду 2’ только в случае успешного выполнения ‘команды 1’.
3) Выполнение нескольких команд Linux одновременно с помощью оператора логического OR (||)
Если вы хотите выполнить следующую команду только в случае неудачи предыдущей, объедините их оператором ‘||’.
Оператор ‘OR’ выполнит ‘команду 2’, только если ‘команда 1’ не выполнится или вернется ошибка.
Аналогично, если ‘команда 1’ выполнена успешно, ‘команда 2’ не будет выполнена.
command 1 || command 2 || … command N
Например: Здесь первая команда выполнена успешно, потому что мы вошли в каталог ‘cpufetch’, поэтому команда 2 ‘ls -lh’ не выполняется.
cd cpufetch || ls -lh
При повторном выполнении вышеуказанной команды ‘Команда 2’ выполнилась успешно, так как ‘Команда 1’ завершилась неудачно.
Итак, мы можем перечислить содержимое каталога ‘cpufetch’.
cd cpufetch || ls -lh bash: cd: cpufetch: Not a directory total 100K -rw-r—r— 1 itisgood users 3.0K Jul 29 18:20 CONTRIBUTING.md -rwxr-xr-x 1 itisgood users 74K Jul 29 18:28 cpufetch -rw-r—r— 1 itisgood users 2.4K Jul 29 18:20 cpufetch.1 drwxr-xr-x 1 itisgood users 98 Jul 29 18:20 doc -rw-r—r— 1 itisgood users 1.1K Jul 29 18:20 LICENSE -rw-r—r— 1 itisgood users 2.1K Jul 29 18:20 Makefile drwxr-xr-x 1 itisgood users 132 Jul 29 18:20 pictures -rw-r—r— 1 itisgood users 5.0K Jul 29 18:20 README.md drwxr-xr-x 1 itisgood users 24 Jul 29 18:20 src
В этом руководстве мы показали вам различные способы объединения и эффективного выполнения нескольких команд Linux с помощью оператора с запятой (;), логического оператора AND () и логического оператора OR (||).
Если у вас есть вопросы или пожелания, не стесняйтесь оставлять комментарии!
- Три различных способа дублирования установленных пакетов на нескольких машинах Linux
- Как записать вывод команды top в файл
- Как изменить или переименовать точку монтирования на Linux
- Работа с именами файлов с пробелами в системах Linux
- Удаление пакетов, установленных в определенную дату/время в системах Linux
Источник: itisgood.ru
Параллельное выполнение команд в bash
По умолчанию команды в bash выполняются последовательно, при необходимости, можно обеспечить параллельное выполнение команд.
Запуск команд в фоновом режиме
Для параллельного выполнения команд можно использовать запуск команд в фоне, со следующим синтаксисом
command sleep 6 echo 2 sleep 8 echo 4 wait
если выполнять все команды последовательно, скрипт выполнится за 35 секунд, но за счет использования параллельного выполнения, время работы скрипта составило 9 секунд
time ./test.sh 1 2 3 4 5 real 0m9.007s user 0m0.014s sys 0m0.003s
Перенаправление вывода
Для параллельного выполнение команд, можно использовать пайпы. Когда вывод одной команды, перенаправляется на вход другой, при этом процессы выполняются параллельно
command1 | command2 | command3
Источник: g-soft.info