Заполните четыре слота параллельных процессов постоянно, даже когда некоторые заканчивают - PullRequest
0 голосов
/ 04 мая 2018

У меня есть скрипт, который запускает пакеты из 4 процессов одновременно, мне все равно, чтобы получить коды возврата каждого процесса. Я никогда не хочу запускать более 4 процедур одновременно. Проблема с нижеследующим подходом состоит в том, что он не заполняет до 4 процедур одновременно. Например, если proc2 и proc3 закончились раньше, я бы хотел, чтобы proc 5 и 6 запускались, а не только начинались после завершения 1-4. Как мне добиться этого в bash?

run_func_1 &
run_func_2 &
run_func_3 &
run_func_4 &
wait
run_func_5 &
run_func_6 &
run_func_7 &
run_func_8 &
wait

Ответы [ 2 ]

0 голосов
/ 08 мая 2018

С GNU Parallel это так же просто, как:

parallel -j4 ::: run_func_{1..8}

Просто запомните export -f функции.

Если GNU Parallel не установлен, используйте

parallel --embed > new_script

для генерации сценария оболочки, который встраивает GNU Parallel. Вы тогда просто измените конец new_script.

По умолчанию он запускает одно задание на ядро ​​процессора. Это можно настроить с помощью --jobs.

GNU Parallel - это общий параллелизатор, позволяющий легко запускать задания параллельно на одной и той же машине или на нескольких машинах, к которым у вас есть доступ по ssh.

Если у вас есть 32 различных задания, которые вы хотите запустить на 4 процессорах, прямой способ распараллеливания - запустить 8 заданий на каждом процессоре:

Simple scheduling

GNU Parallel вместо этого порождает новый процесс после его завершения - поддерживая активные процессоры и, таким образом, экономя время:

GNU Parallel scheduling

Установка

В целях безопасности вам следует установить GNU Parallel с менеджером пакетов, но если GNU Parallel не упакован для вашего дистрибутива, вы можете выполнить личную установку, которая не требует root-доступа. Это можно сделать за 10 секунд, выполнив следующее:

$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
   fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 3374ec53bacb199b245af2dda86df6c9
12345678 3374ec53 bacb199b 245af2dd a86df6c9
$ md5sum install.sh | grep 029a9ac06e8b5bc6052eac57b2c3c9ca
029a9ac0 6e8b5bc6 052eac57 b2c3c9ca
$ sha512sum install.sh | grep f517006d9897747bed8a4694b1acba1b
40f53af6 9e20dae5 713ba06c f517006d 9897747b ed8a4694 b1acba1b 1464beb4
60055629 3f2356f3 3e9c4e3c 76e3f3af a9db4b32 bd33322b 975696fc e6b23cfb
$ bash install.sh

Другие варианты установки см. http://git.savannah.gnu.org/cgit/parallel.git/tree/README

Узнать больше

См. Больше примеров: http://www.gnu.org/software/parallel/man.html

Смотрите вступительные видеоролики: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Пройдите учебник: http://www.gnu.org/software/parallel/parallel_tutorial.html

Подпишитесь на рассылку, чтобы получить поддержку: https://lists.gnu.org/mailman/listinfo/parallel

0 голосов
/ 05 мая 2018

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

Возможно, вы сможете адаптировать этот скрипт к тому, что вам нужно, но я надеюсь, что вы увидите мои намерения.

Вот сценарий:

#!/bin/bash

f1() { echo Started f1; sleep 10; echo Finished f1; }
f2() { echo Started f2; sleep 8; echo Finished f2; }
f3() { echo Started f3; sleep 12; echo Finished f3; }
f4() { echo Started f4; sleep 14; echo Finished f4; }
f5() { echo Started f5; sleep 7; echo Finished f5; }

declare -r MAX_WORKERS=2
declare -a worker_pids
declare -a jobs=('f1' 'f2' 'f3' 'f4' 'f5')

available_worker_index() {
    # If number of workers is less than MAX_WORKERS
    # We still have workers that are idle
    declare worker_count="${#worker_pids[@]}"
    if [[ $worker_count -lt $MAX_WORKERS ]]; then
        echo "$worker_count"
        return 0
    fi

    # If we reached this code it means
    # All workers are already created and executing a job
    # We should check which of them finished and return it's index as available
    declare -i index=0
    for pid in "${worker_pids[@]}"; do
        is_running=$(ps -p "$pid" > /dev/null; echo "$?")
        if [[ $is_running != 0 ]]; then
            echo "$index"
            return 0
        fi
        index+=1
    done

    echo "None"
}

for job in "${jobs[@]}"; do
    declare worker_index
    worker_index=$(available_worker_index)
    while [[ $worker_index == "None" ]]; do
        # Wait for available worker
        sleep 3
        worker_index=$(available_worker_index)
    done

    # Run the job in background
    "$job" &

    # Save it's pid for later
    pid="$!"
    worker_pids["$worker_index"]="$pid"
done

# Wait all workers to finish
wait

Вы можете легко изменить размер рабочего пула, только изменив переменную MAX_WORKERS.

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