Як запустити паралельні процеси та об'єднати результати, коли вони закінчені


17

У мене є скрипт bash shell, в якому я передаю деякі дані через приблизно 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 не працюватиме на потоці чи на каналі.



BTW, чи нормально для вас використовувати сценарії 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.

Дивіться, наприклад, це питання .


Thx, це добре виглядає. Я спробую це, якщо вищезгадане не вийде.
Стівен Хендерсон

Thx знову, я був в курсі очікування, але трохи погуглившись, був збентежений тим, як це працює з різними PID і т. Д. Я відчуваю, що зараз я бачу, що це просто "чекання"
Стівен Хендерсон,

12

Відповідь cxw без сумніву є кращим рішенням, якщо у вас є лише 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 Parale_tutorial). Ви командний рядок вас за це люблять.

Привіт THX. На даний момент у мене є два файли, але у мене є 24 процесори, тому я відчував спокусу спробувати запустити багато пар одночасно - хоча як людина, яка не є комп'ютерною наукою, мені незрозуміло, чи зробить це вузьким місцем читання диска. можливо, я його смоктатиму і побачу;)
Стівен Хендерсон

@StephenHenderson, залежно від розміру, файли все ще можуть знаходитись у кеші. Якщо швидкість критична, ви можете просто використовувати tmpfs (а файли <<<, то ваша оперативна пам'ять).
Maciej Piechotka

1
@StephenHenderson Кількість паралельних завдань можна регулювати за допомогою -j, тому спробуйте -j4, і якщо сервер не перевантажується, спробуйте -j6 і т.д. . Також подивіться на --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

Таким чином, ви фоновуєте обидва конвеєра, але все ще чекаєте, поки вони завершать виконання, перш ніж об'єднати свій висновок у stdin, який оцінюється у документі тут і передається 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
)

Я раніше демонстрував ці концепції. Напевно, найкращі демонстрації тут і тут .


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колеса?
Джон У. Сміт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.