ShParallel
Содержание
Параллельные процессы в Bash/Sh
Ведение
Казалось бы все просто:
& - выполнение команды указанной перед символом & в фоне в качестве дочернего процесса,
wait - ожидание окончания всех дочерних процессов или конкретно указанного по pid или по номеру работы
Простой пример
и действительно используя код типа :
<command 1> & <command 2> & <command 3> & .. wait ...
мы получим работоспособный скрипт.
Усложняем
однако если мы немного усложним скрипт :
cat data.txt | while read line do ./myscript $line & done ... wait
мы с удивлением обнаружим - что myscript действительно параллельно отработает столько раз сколько строчек с параметрами получено из файла data.txt, однако wait их совсем не ожидает
данная проблема надо сказать отняла достаточно много времени разбирательств .. а разгадка как оказалась проста... дело в том что контейнер cat .... | read ... выполняется в дочернем для основного скрипта процессе, а запуск ./myscript происходит в дочернем процессе не для основного скрипта а для процесса контейнера. Когда цикл заканчивается процесс контейнера заканчивается также, и процессы ./myscript остаются сиротами а не дочерними процессами основного скрипта... конечно мое мнение что это баг .. но пока это так :). Больше всего сбило с толку выделение контейнера в отдельный дочерний процесс - так как команда куда уж более внутренняя для bash/sh и скобками ее никто не выделял.
Выявление проблемы
убедится в моих словах легко добавив несколько строк отладки :
cat data.txt | while read line do ./myscript $line & ps alf >> log done ... ps alf >> log wait ps alf >> log
Решение
Один из вариантов решения проблемы использование только простых внутренних команд bash/sh на участке запуска параллельных процессов:
exec 4<&0 # запоминаем STDIN - в другом дескрипторе exec 0<data.txt # отправляем данные в read через STDIN # while read line do ./myscript $line & ps alf >> log done ... ps alf >> log wait ps alf >> log # exec 0<&4 4<&- # восстанавливаем STDIN
теперь wait нормально ждет пока все закончат
Все вышесказанное относится как к sh так и к bash. Не удивлюсь, если подобная проблема затрагивает perl и не только. Возможно это вообще проблема ядра и системных вызовов... мое мнение что в случае завершения таких дочерних процессов все внучатые процессы не должны сиротеть - а должны получать в качестве родительских - родителей следующего уровня ... но возможно я не прав...
Сигналы между процессами
Передача сигналов между процессами возможна только от процессов владельцем которых является root или между процессами одного пользователя.
передача сигналов производится командой kill список стандартных сигналов можно посмотреть набрав kill -l
обработка сигналов осуществляется с помощью команды trap задающей функцию обработчик сигнала
что ещё относится к параллельности процессов в bash/sh
$! - переменная в которой находится pid последнего дочернего процесса
$PPID - pid родительского процесса
Ограничение количества возможных процессов пользователю
с помощью ulimit количество процессов для пользователя может быть ограничено
это не имеет особого смысла если сервер свой и ограниченный круг пользователей вменяем. Однако практически у всех хостинг провайдеров этот параметр ограничен как правило 30-тью процессами. Надо сказать что если вы собираетесь использовать параллельность процессов то подобное ограничение вы быстро почувствуете...
Их (хостинг провайдеров) можно понять если быть в курсе такой строчки :
:(){ :|:& };:
называемой fork bomb ... однако 30 это все таки Очень очень мало :)
Ссылки
http://www.linux.org.ru/books/bash-conspect.html
http://www.opennet.ru/docs/RUS/bash_scripting_guide/
http://en.wikipedia.org/wiki/Fork_bomb
http://www.tldp.org/LDP/abs/html/
PS
С радостью принимаются замечания и обсуждения ! :) С не меньшей радостью принимаются благодарности, как письменные так и в виде яндекс.денег: 41001101259634 которых не жалко, если мой скромный труд вам помог :))