Поток Bash: ожидание завершения всех рабочих потоков не работает? - PullRequest
12 голосов
/ 14 февраля 2010

Я пишу небольшой скрипт, который будет создавать архивы в главном потоке, и после того, как каждый архив будет завершен, будет создан новый поток, вызвав функцию, которая позаботится о загрузке этих архивов. Причина, по которой я хочу, чтобы загрузка выполнялась в фоновом режиме, заключается в том, что другой архив может быть создан во время загрузки предыдущих архивов.

Проблема у меня в самом конце сценария. То есть основной поток не ждет завершения загрузки всех потоков перед выходом. Посмотрите на следующий упрощенный скрипт (я удалил / изменил части кода, не связанные с проблемой)

function func {
for files in /home/somewhere/
  do
    echo "Uploading $1" &
  done
wait
}

find /home/some/path -type f | while read filename ; do
  echo "Creating archive of $filename"
  func $somevariable &
done

wait

Все выполняется очень хорошо до тех пор, пока не будет создан последний архив, затем сценарий завершается до завершения всех потоков func, в результате чего многие файлы не загружаются.

Спасибо за ваши идеи.

Ответы [ 5 ]

13 голосов
/ 14 февраля 2010

Обновление: хорошие моменты в комментарии.

Итак, на второй взгляд выясняется, что проблема заключается в подоболочке, которая создается каналом в цикле. Это хороший способ структурировать скрипт, но вам нужно сделать последнее ожидание в оболочке, которая запускает фоновые задачи.

Так что сделайте что-то вроде этого:

find /home/some/path -type f | (while read filename; do
    echo "Creating archive of $filename"
    func $somevariable &
  done
  wait
)
6 голосов
/ 14 февраля 2010

Tricky!Проблема в том, что этот блок

find /home/some/path -type f | while read filename ; do
  ...
done

Создает подоболочку.В этой подоболочке создаются рабочие места func $ somevariable.Родительская оболочка видит, что все фоновые задания , созданные им , завершены, она не отслеживает фоновые задания, созданные порожденными им субоболочками.

Самое простое решение - создать фоновые заданиявместо родительской оболочки.Вы можете избежать создания подоболочки, не используя канал:

while read filename ; do
  ...
done < <(find /home/some/path -type f)

Ну, это создает a subshell --- для поиска - но блок while больше не находится вподшкура.

Обратите внимание, что вышесказанное работает только под bash.(Не знаю насчет ksh или zsh, возможно, он там тоже работает. Но он не будет работать под пеплом и другими производными sh.)

3 голосов
/ 14 февраля 2010

Если вы выполните wait без аргументов, он должен дождаться завершения текущих активных дочерних процессов.

Проблема, вероятно, заключается в том, что «все активные в данный момент дочерние процессы» не означают того, что, по вашему мнению, означает в этом контексте. В частности, если вы создаете конвейеры в подоболочке, не совсем понятно, ожидают ли их в родительской оболочке.

Я подозреваю, что wait на самом деле ожидает только процессы / конвейеры, которые отображаются в выводе jobs. Попробуйте несколько экспериментов ...

Возможной альтернативой может быть захват идентификаторов дочерних процессов и выполнение вызова wait n для каждого идентификатора.

0 голосов
/ 17 июня 2019

Вы можете попробовать этот скрипт. Это именно так. https://github.com/pabloniklas/BASH/blob/master/lib_cpu.sh

0 голосов
/ 14 февраля 2010

Вы можете выполнить цикл до тех пор, пока команда jobs не вернет ничего в качестве альтернативного метода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...