Как запустить параллельные процессы и объединить результаты после их завершения

Как запустить параллельные процессы и объединить результаты после их завершения

У меня есть скрипт оболочки 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.

решение1

Используйте wait. Например:

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

воля:

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

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

решение2

Ответ 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). Ваша командная строка будет вам за это благодарна.

решение3

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

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

Таким образом, вы переводите оба конвейера в фоновый режим, но все равно ждете, пока они закончат выполнение, прежде чем объединить их вывод в stdin, который оценивается в here-документе и передается в 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
)

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

решение4

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

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

Связанный контент