ShParallel

Материал из OpenWiki
Перейти к: навигация, поиск

Параллельные процессы в 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 которых не жалко, если мой скромный труд вам помог :))