Параллельная обработка в bash с "&" и ожиданием - PullRequest
0 голосов
/ 09 ноября 2019

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


RESTORE(){

sleep 10 && echo "restore done" &

}


RESTORE_CALLER() {


echo "waiting for any restore with pid ${current_restore_pid}"
wait ${current_restore_pid}


echo "Calling restore"
RESTORE &
current_restore_pid=$!



}


DUMP(){

for ((i=0;i<5;i++));do
echo "dumping "

echo "restore caller"
RESTORE_CALLER &

done

} 

DUMP 

Ответы [ 4 ]

3 голосов
/ 10 ноября 2019

Просто передайте это:

seq 1 5 |
while read l; do
    DUMP > "$l".dump
    echo "$l"
done |
while read l; do
    RESTORE < "$l".dump
    echo "$l"
done

Но, вероятно, лучше использовать другой дескриптор для передачи данных между каналами, чтобы журналы печатались хорошо:

seq 1 5 |
while read l; do
   DUMP "$l"
   echo "$l" >&3
done 3> >(
    while read l; do
        RESTORE "$l"
    done
) |
cat

Пример выполнения сдве заглушки:

DUMP() {
    sleep 0.$(($RANDOM % 10))
    echo "DUMPING $1"
}
RESTORE() {
    sleep 0.$(($RANDOM % 10))
    echo "RESTORING $1"
}

выглядит круто:

DUMPING 1
RESTORING 1
DUMPING 2
RESTORING 2
DUMPING 3
DUMPING 4
DUMPING 5
RESTORING 3
RESTORING 4
RESTORING 5

На конце | cat необходим для синхронизации процесса подстановки.

Что в этом крутогоВы можете использовать такие инструменты, как xargs, чтобы легко распараллелить функции DUMP и RESTORE, например, 3 DUMP с параллельной и 2 RESTORE параллельной:

DUMP() {
    echo "DUMPING $1"
    sleep 0.$(($RANDOM % 10))
    echo "DUMPED $1"
}
RESTORE() {
    echo "RESTORING $1"
    sleep 0.$(($RANDOM % 10))
    echo "RESTORED $1"
}

export -f DUMP RESTORE
seq 1 5 |
xargs -n1 -P3 bash -c 'DUMP "$1"; echo "$1" >&3' -- 3> >(
    xargs -n1 -P2 bash -c 'RESTORE "$1"' --
) | cat

И этовыглядит даже круче:

DUMPING 1
DUMPING 2
DUMPING 3
DUMPED 3
RESTORING 3
DUMPING 4
DUMPED 4
RESTORED 3
RESTORING 4
DUMPING 5
DUMPED 1
RESTORING 1
RESTORED 4
DUMPED 2
RESTORING 2
DUMPED 5
RESTORED 2
RESTORING 5
RESTORED 1
RESTORED 5
1 голос
/ 09 ноября 2019

Публикация альтернативного ответа для обеспечения неограниченного параллельного дампа при одновременном разрешении только одного одновременного восстановления в любой точке.

Решение относительно прямолинейное: задания дампа разветвляются, отслеживая каждый PID в массиве. Цикл по заданию восстановления и проверка для каждого задания восстановления, которое завершено соответствующими заданиями дампа, и что предыдущие задания восстановления также завершены.

#! /bin/bash

RESTORE(){
        echo "Start Restore $1 - $$"
        sleep 10
        echo "End Restore $1 - $$"
}

DUMP() {
        echo "Start Dump $1 - $$"
        sleep 15
        echo "End Dump $1 - $$"
}


RUN_ALL(){

for ((i=0;i<5;i++));do
        DUMP $i &
        dump_pid[$i]=$!
done
restore_pid=
for ((i=0;i<5;i++));do
        wait ${dump_pid[i]}
        [ "$restore_pid" ] && wait $restore_pid
        RESTORE $i &
        restore_pid=$!
done

}

RUN_ALL
1 голос
/ 09 ноября 2019

Я полагаю, что ваш скрипт завершится неудачно, потому что каждый вызов RESTORE_CALLER & создает новый процесс и новый current_restore_pid, который не является общим.

Если вы разделите процедуру восстановления на отдельный скрипт,Вы можете использовать flock(1), чтобы установить эксклюзивную блокировку так, чтобы одновременно выполнялось только одно восстановление (порядок не гарантирован):

#!/bin/bash

lockfile=$(mktemp)
for ((i=0;i<5;i++)); do
    dump-function args
    flock -x "$lockfile" restore-program args &
done
rm "$lockfile"
0 голосов
/ 09 ноября 2019

Я считаю, что логика была правильной, но в реализации есть два места, где задачи были отправлены в фоновый режим по ошибке:

  • В RESTORE '&' on 'sleep ...',заставить RESTORE немедленно возвращаться.
  • В DUMP '&' в 'RESTORE_CALLER ...' разветвляет восстановление в отдельную вложенную оболочку, предотвращая ожидание работы (процессы могут ожидать только прямых потомков).

В конце, есть только один '&' - для операции RESTORE, которая является единственной операцией для перехода в фоновый режим.


RESTORE(){
# Remove backgroup
# sleep 10 && echo "restore done" &
sleep 10 && echo "restore done"
}


RESTORE_CALLER() {
echo "waiting for any restore with pid ${current_restore_pid}"
wait ${current_restore_pid}
echo "Calling restore"
RESTORE &
current_restore_pid=$!
}


DUMP(){
for ((i=0;i<5;i++));do
echo "dumping "

echo "restore caller"
# Remove Background
# RESTORE_CALLER &
RESTORE_CALLER
done
} 

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