Распараллеливание задачи в bash-скрипте

Искусство написания bash скриптов. Делимся своими наработками
Ответить
Аватара пользователя
ZEN
Администратор
Сообщения: 1349
Зарегистрирован: 27 сен 2012, 18:23
Темы: 206
Откуда: Украина, Одесса
Статус: Не в сети

Распараллеливание задачи в bash-скрипте

Сообщение ZEN » 28 окт 2015, 12:33

Ниже написанный скрипт сравнивает <title> на сайте opennet.ru с текстом из массива DATA. При этом запросы к opennet.ru выполняются в фоне ( получаем этакий fork(), что бы выполнить задачу быстрее ).

Код скрипта

Код: Выделить всё

#!/usr/bin/env bash

DATA=(
    "1 OpenNews: Каналу #rusunix 2 года."
    "3 OpenNews: Тестирование системы UNIX новостей"
    "5 OpenNews: Hurd живет!"
    "9 OpenNews: Обзор статей в журнале "Открытые системы. СУБД" N 11-12 за 1999 г."
    "11 OpenNews: Вышла новая версия программы KDevelop (1.2)."
    "13 OpenNews: Зашифрование swap в ядре OpenBSD"
);

for ITEM in "${DATA[@]}"
do
    CPU_CORES=$(grep -m1 'cpu cores' /proc/cpuinfo | sed 's/.*: \([0-9]*\)/\1+1/g' | bc);

    # Количество фоновых процессов
    JOB_PIDS=( $(jobs -p) );

    # Ожидаем завершение фоновой задачи,
    # если фоновых задач больше чем количество ядер + 1
    test "${#JOB_PIDS[@]}" -ge "$CPU_CORES" && wait;

    NEWS_ID="${ITEM/ */}";
    LOCAL_NEWS_NAME="${ITEM#* }";
    REMOTE_NEWS_NAME=$(
        wget -UTest -q "http://www.opennet.ru/opennews/art.shtml?num=$NEWS_ID" -O - | awk -F'>|<' '/<title>/{print $3; exit;}' | iconv -f koi8-r
    ) && {
        test "$LOCAL_NEWS_NAME" = "$REMOTE_NEWS_NAME" && STATUS="OK" || STATUS="FAIL";
        echo "$NEWS_ID: '$LOCAL_NEWS_NAME' <=> '$REMOTE_NEWS_NAME' = $STATUS";
    } & # <== Код начиная с инициализации пемеренной 'REMOTE_NEWS_NAME' до этой строки будет выполняться в фоне
done;

wait;
exit 0;
Как видно по выхлопу скрипта, wget отработал в другом порядке, несмотря на то, скрипт пробегал по массиву DATA подряд => 1,3,5,9,11,13

Код: Выделить всё

zen@debian:~$ ./test.sh
1: 'OpenNews: Каналу #rusunix 2 года.' <=> 'OpenNews: Каналу #rusunix 2 года.' = OK
5: 'OpenNews: Hurd живет!' <=> 'OpenNews: Hurd живет!' = OK
3: 'OpenNews: Тестирование системы UNIX новостей' <=> 'OpenNews: Тестирование системы UNIX новостей' = OK
13: 'OpenNews: Зашифрование swap в ядре OpenBSD' <=> 'OpenNews: Зашифрование swap в ядре OpenBSD' = OK
11: 'OpenNews: Вышла новая версия программы KDevelop (1.2).' <=> 'OpenNews: Вышла новая версия программы KDevelop (1.2).' = OK
9: 'OpenNews: Обзор статей в журнале "Открытые системы. СУБД" N 11-12 за 1999 г.' <=> 'OpenNews: Обзор статей в журнале "Открытые системы. СУБД" N 11-12 за 1999 г.' = OK
В боевых условиях, скрипт подобный этому, бегал по 835 ссылкам. С распараллеливанием задачи скрипт отработал за 3 минуты, а без распараллеливания - 10 минут.
бог создал труд и обезьяну
чтоб получился человек
а вот пингвина он не трогал
тот сразу вышел хорошо

Аватара пользователя
mivanchenko
Модератор
Сообщения: 14
Зарегистрирован: 27 ноя 2013, 17:00
Темы: 5
Контактная информация:
Статус: Не в сети

Re: Распараллеливание задачи в bash-скрипте

Сообщение mivanchenko » 29 сен 2016, 15:30

Код: Выделить всё

generate lines | xargs -n1 -P8 sh -c 'do something with a line $0'
-n: количество строк, выделенных текущему процессу
-P: количество одновременно работающих процессов

http://perlist.blogspot.com/2015/03/par ... -bash.html

Аватара пользователя
ZEN
Администратор
Сообщения: 1349
Зарегистрирован: 27 сен 2012, 18:23
Темы: 206
Откуда: Украина, Одесса
Статус: Не в сети

Re: Распараллеливание задачи в bash-скрипте

Сообщение ZEN » 29 сен 2016, 15:38

ага, есть еще parallel, но его нужно отдельно устанавливать. Да, xargs не всегда имел параметр -P. Например, в установленном busybox на Android 6 данный параметр не поддерживается :(
бог создал труд и обезьяну
чтоб получился человек
а вот пингвина он не трогал
тот сразу вышел хорошо

Аватара пользователя
mivanchenko
Модератор
Сообщения: 14
Зарегистрирован: 27 ноя 2013, 17:00
Темы: 5
Контактная информация:
Статус: Не в сети

Re: Распараллеливание задачи в bash-скрипте

Сообщение mivanchenko » 17 окт 2016, 17:20

Кстати, можно указать количество процессов равным количеству доступных процессоров для xargs:

Код: Выделить всё

xargs --max-procs=$(getconf _NPROCESSORS_ONLN)

Аватара пользователя
lumberjack
Модератор
Сообщения: 1009
Зарегистрирован: 30 сен 2012, 04:04
Темы: 152
Откуда: Сургут
Статус: Не в сети

Re: Распараллеливание задачи в bash-скрипте

Сообщение lumberjack » 18 окт 2016, 06:28

имхо, можно и nproc :)

Ответить

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 0 гостей