Как запустить параллельные процессы и объединить результаты, когда оба закончили

17

У меня есть скрипт оболочки bash, в котором я передаю некоторые данные через 5 или 6 различных программ, а затем окончательные результаты в файл с разделителями табуляции.

Затем я делаю то же самое снова для отдельного подобного набора данных и выводлю во второй файл.

Затем оба файла вводятся в другую программу для сравнительного анализа. например, чтобы упростить

Data1 | this | that |theother | grep |sed | awk |whatever > Data1Res.csv
Data2 | this | that |theother | grep |sed | awk |whatever > Data2Res.csv
AnalysisProg -i Data1res.csv Data2res.csv

Мой вопрос: как я могу сделать шаги 1 и 2 запущенными одновременно (например, с помощью &), но запускать только шаг 3 (AnalysisProg), когда оба завершены?

Спасибо

ps AnalysisProg не будет работать в потоке или fifo.

Стивен Хендерсон
источник
Проверьте это: pebblesinthesand.wordpress.com/2008/05/22/…
Bichoy
Кстати, это нормально для вас, чтобы использовать Perl-скрипты? Это может значительно упростить для вас этот вопрос, и вы можете очень эффективно реализовать эту постобработку и без труда запустить ее параллельно.
Бичой
Perl .. не так много, нет :(
Стивен Хендерсон,
1
Здесь я продемонстрирую, как разделить входные данные по каналам teeи обработать их двумя параллельными grepпроцессами: unix.stackexchange.com/questions/120333/…
mikeserv
И здесь я демонстрирую, как использовать простые конструкции оболочки, чтобы полностью задокументировать процесс так, как это nohupвозможно, но при этом поддерживая средства связи с процессом: unix.stackexchange.com/questions/121253/…
mikeserv

Ответы:

27

Использование wait. Например:

Data1 ... > Data1Res.csv &
Data2 ... > Data2Res.csv &
wait
AnalysisProg

будет:

  • запустить каналы Data1 и Data2 в качестве фоновых заданий
  • ждать, пока они оба закончат
  • запустите AnalysisProg.

Смотрите, например, этот вопрос .

CXW
источник
Спасибо, это выглядит хорошо. Я попробую это, если вышеупомянутое не работает.
Стивен Хендерсон
Спасибо еще раз, я был в курсе ожидания, но, немного погуглив, был смущен тем, как это работает с разными PID и т. Д. Я чувствую себя глупо, теперь я вижу, что это просто «подождите»
Стивен Хендерсон,
12

Ответ cxw, без сомнения, является предпочтительным решением, если у вас есть только 2 файла. Если эти 2 файла являются просто примерами, а у вас в действительности есть 10000 файлов, то решение «&» не будет работать, так как это приведет к перегрузке вашего сервера. Для этого вам понадобится такой инструмент, как GNU Parallel:

ls Data* | parallel 'cat {} | this | that |theother | grep |sed | awk |whatever > {}res.csv
AnalysisProg -i *res.csv

Чтобы узнать больше о GNU Parallel:

  • Посмотрите вступительное видео для быстрого ознакомления: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
  • Пройдите учебник (man parallel_tutorial). Ваша командная строка будет любить вас за это.
Оле Танге
источник
Привет, спасибо. В настоящее время у меня есть два файла, но у меня 24 процессора, поэтому я испытывал желание попробовать запустить несколько пар одновременно - хотя я не специалист в области компьютерных наук, и я не уверен, что узкое место в чтении с диска будет целесообразным. может я его пососу и посмотрю;)
Стивен Хендерсон
@StephenHenderson, в зависимости от размера, файлы все еще могут быть в кеше. Если скорость критична, вы можете просто использовать tmpfs (а файлы <<<, то ваша RAM).
Мацей Пехотка
1
@StephenHenderson Количество параллельных заданий можно настроить с помощью -j, поэтому попробуйте -j4, а если сервер не перегружается, попробуйте -j6 и т. Д. Но будьте готовы нажать CTRL-C: GNU Parallel - отличный инструмент для быстрой перегрузки серверов. , Также взгляните на --load.
Оле Танге
1

Один из способов сделать это может выглядеть примерно так:

AnalysisProg <<PREPROCESS /dev/stdin
$( 
{   process1=$( pipe | line | 1 >&2 & echo $! )
    process2=$( pipe | line | 2 >&2 & echo $! )
    while ps -p $process1 $process2 >/dev/null; do
        sleep 1
    done
} 2>&1
)
#END
PREPROCESS

Таким образом, вы создаете фоновый режим для обоих конвейеров, но все еще ждете, пока они завершат выполнение, прежде чем объединить их вывод в стандартный ввод, который оценивается в данном документе и передается AnalysisProg. Если вы можете использовать waitэто, то это даже лучше, чем while psцикл, но, в зависимости от оболочки, waitможет возражать, если вы дадите ему команду ждать процесса, который не является потомком текущей оболочки.

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

AnalysisProg 3<<PREPROCESS /dev/fd/3 /dev/stderr
$(
process1=$(... >&2 ...) 2>/dev/fd/3
...
} 3>/dev/fd/3 2>/dev/stderr
)

Я продемонстрировал эти концепции раньше. Наверное, лучшие демо здесь и здесь .

mikeserv
источник
0

Попробуйте использовать это.

rm -f Data1Res.csv
rm -f Data2Res.csv
Data1 | this | that |theother | grep |sed | awk |whatever > Data1Res.csv &
Data2 | this | that |theother | grep |sed | awk |whatever > Data2Res.csv &
while true
do
  ps aux | grep -v grep | grep -i -E 'Data1Res.csv|Data2Res.csv' &> /dev/null
  if [ $? -ne 0 ]
  then
    AnalysisProg -i Data1res.csv Data2res.csv
    exit 0
  fi
done
Ренан Висенте
источник
Ну, это тяжелый. Разве это не как изобретать waitвелосипед?
Джон У. С. Смит,