БАШ: паралельний пробіг


4

У мене є Баш скрипт , який приймає в якості вхідних даних три масивів з однаковою довжиною: METHODS, INFILESі OUTFILES.

Цей скрипт дозволить METHODS[i]вирішити проблему INFILES[i]і збереже результат OUTFILES[i]для всіх індексів i( 0 <= i <= length-1).

Кожен елемент у METHODS- це рядок форми:

$HOME/program/solver -a <method>

де solver - це програма, яку можна назвати наступним чином:

$HOME/program/solver -a <method> -m <input file> -o <output file> --timeout <timeout in seconds>

Сценарій вирішує всі проблеми паралельно і встановлює ліміт часу виконання для кожного примірника до 1 години (хоча деякі методи можуть вирішити деякі проблеми дуже швидко), як слід:

#!/bin/bash
source METHODS
source INFILES
source OUTFILES

start=`date +%s`

## Solve in PARALLEL
for index in ${!OUTFILES[*]}; do 
    (alg=${METHODS[$index]}
    infile=${INFILES[$index]}
    outfile=${OUTFILES[$index]}

    ${!alg}  -m $infile -o $outfile --timeout 3600) &
done
wait


end=`date +%s`

runtime=$((end-start))
echo "Total runtime = $runtime (s)"
echo "Total number of processes = ${#OUTFILES[@]}"

У вищесказаному маю length = 619. Я подав цей баш в кластер із 70 доступними процесорами, на що, щоб виконати всі завдання, потрібно максимум 9 годин. Однак насправді це не так. Використовуючи topкоманду для дослідження, я виявив, що працює лише два-три процеси (стан = R), а всі інші сплять (стан = D).

Що я роблю неправильно, будь ласка?

Крім того, я дізнався, що паралель GNU був би набагато кращим для виконання паралельних завдань. Як я можу використовувати його для вищезазначеного завдання?

Велике спасибі за вашу допомогу!

Оновлення: моя перша спроба з GNU паралельно:

Ідея полягає в тому, щоб записати всі команди у файл, а потім використовувати GNU паралельно для їх виконання:

#!/bin/bash
source METHODS
source INFILES
source OUTFILES

start=`date +%s`    

## Write to file
firstline=true
for index in ${!OUTFILES[*]}; do 
    (alg=${METHODS[$index]}
    infile=${INFILES[$index]}
    outfile=${OUTFILES[$index]}
    if [ "$firstline" = true ] ; then
        echo "${!alg}  -m $infile -o $outfile --timeout 3600" > commands.txt
        firstline=false
    else
        echo "${!alg}  -m $infile -o $outfile --timeout 3600" >> commands.txt
    fi
done

## Solve in PARALLEL
time parallel :::: commands.txt

end=`date +%s`

runtime=$((end-start))
echo "Total runtime = $runtime (s)"
echo "Total number of processes = ${#OUTFILES[@]}"

Що ти думаєш?

Оновлення 2: я використовую GNU паралельно і маю ту саму проблему. Ось результат top:

top - 02:05:25 up 178 days,  8:16,  2 users,  load average: 62.59, 59.90, 53.29
Tasks: 596 total,   7 running, 589 sleeping,   0 stopped,   0 zombie
Cpu(s): 12.9%us,  0.9%sy,  0.0%ni, 63.3%id, 22.9%wa,  0.0%hi,  0.1%si,  0.0%st
Mem:  264139632k total, 260564864k used,  3574768k free,     4564k buffers
Swap: 268420092k total, 80593460k used, 187826632k free,    53392k cached

  PID USER     PR  NI  VIRT  RES  SHR S %CPU %MEM   TIME+   COMMAND
28542 khue     20   0 7012m 5.6g 1816 R  100  2.2  12:50.22 opengm_min_sum
28553 khue     20   0 11.6g  11g 1668 R  100  4.4  17:37.37 opengm_min_sum
28544 khue     20   0 13.6g 8.6g 2004 R  100  3.4  12:41.67 opengm_min_sum
28549 khue     20   0 13.6g 8.7g 2000 R  100  3.5   2:54.36 opengm_min_sum
28551 khue     20   0 11.6g  11g 1668 R  100  4.4  19:48.36 opengm_min_sum
28528 khue     20   0 6934m 4.9g 1732 R   29  1.9   1:01.13 opengm_min_sum
28563 khue     20   0 7722m 6.7g 1680 D    2  2.7   0:56.74 opengm_min_sum
28566 khue     20   0 8764m 7.9g 1680 D    2  3.1   1:00.13 opengm_min_sum
28530 khue     20   0 5686m 4.8g 1732 D    1  1.9   0:56.23 opengm_min_sum
28534 khue     20   0 5776m 4.6g 1744 D    1  1.8   0:53.46 opengm_min_sum
28539 khue     20   0 6742m 5.0g 1732 D    1  2.0   0:58.95 opengm_min_sum
28548 khue     20   0 5776m 4.7g 1744 D    1  1.9   0:55.67 opengm_min_sum
28559 khue     20   0 8258m 7.1g 1680 D    1  2.8   0:57.90 opengm_min_sum
28564 khue     20   0 10.6g  10g 1680 D    1  4.0   1:08.75 opengm_min_sum
28529 khue     20   0 5686m 4.4g 1732 D    1  1.7   1:05.55 opengm_min_sum
28531 khue     20   0 4338m 3.6g 1724 D    1  1.4   0:57.72 opengm_min_sum
28533 khue     20   0 6064m 5.2g 1744 D    1  2.1   1:05.19 opengm_min_sum

( opengm_min_sumє solverвище)

Я здогадуюсь, що деякі процеси споживають стільки ресурсу, що іншим нічого не залишається і входять у стан D?


Процеси в стані D, як правило, чекають вводу / виводу ("диска"). Можливо, вашому кластеру бракує пропускної здатності вводу / виводу.
ікар

@icarus: Велике спасибі, що дуже корисно. Я використовую паралельно GNU, а не waitстикаюся з тією ж проблемою. Як слід далі розслідувати, щоб побачити, що не так?
Khue

Не ясно, що тут щось не так . Багато що залежить від того, що намагається зробити система. Кілька крайніх прикладів, запускаючи зломщик паролів, він може читати лише в одному рядку і не виводити нічого або одного слова, а в середній час використовувати 100% вашого процесора. В іншому крайньому випадку робити резервну копію дерева каталогів без будь-якого стиснення. Це було б майже 100% вводу / виводу, і майже всі процеси були б показані в D. Обидва речі працюють правильно. Вам, напевно, потрібно дізнатися, чи можете ви робити більше workі менше вводу / виводу, або ж отримати більш чи більш швидкі диски
ікар

1
Система, безумовно, голодує вводу / виводу. Система використовує лише 14% (12,9 + 0,9) доступного процесора, вона працює в режимі очікування 63% і чекає 23%. Витрата пам'яті також виглядає дивно, ви використовуєте 256 ГБ оперативної пам’яті та 80 Гб свопу. Після того, як ви почнете використовувати своп, речі можуть ставати дуже повільними . Можливо, буде краще зменшити кількість речей, які ви паралельно працюєте (сподіваємось, просто розрізати навпіл), тому обмін використовуваного свопу майже дорівнює нулю.
ікар

1
Такі програми люблять psі topпоказують лише те, що відбувається в той момент, коли щось запускається. Якщо програма читає багато даних, то є велика ймовірність, що в даний момент topзапущена вона буде чекати диска. Я нічого не знаю про вашу проблему, але, схоже, у вас є машина, яка досить швидка, але не має достатньої пам’яті для того, щоб одночасно запускати всі ваші програми і не вистачає пропускної здатності вводу-виводу. Якщо ви отримуєте доступ до даних послідовно, можливо, стиснення це допоможе? Не забудьте подати мені кредит у докторантурі!
ікар

Відповіді:


2

Короткий зміст коментарів: Машина швидка, але не має достатньо пам’яті для паралельного запуску. Крім того, проблемі потрібно прочитати багато даних, а пропускна здатність диска недостатня, тому процесор простоює більшу частину часу, чекаючи даних.

Перестановка завдань допомагає.

Ще не досліджено стиснення даних, щоб побачити, чи може це покращити ефективну пропускну здатність вводу / виводу диска.


Здається, головне питання пов'язане з програмним забезпеченням, але ваші коментарі та пропозиції були дуже корисними. Чи можете ви бути більш конкретними щодо "стиснення даних"? (будь-яке розуміння того, як це зробити). Дякую.
Khue

@Khue Це залежить від того, як ви використовуєте дані. Якщо ви по суті просто читаєте його як один довгий потік, то стискання його, ймовірно, допоможе. Якщо ви можете стиснути свій файл до третини оригінального розміру (цілком розумно для текстового файлу з gzip), тоді вам потрібно лише прочитати третину кількості байтів з диска. Вам потрібно обробити стислий потік, але, як ми бачили, вам не вистачає процесора. Стиснення потоку фактично зробить ваші диски в 3 рази швидшими. Тут немає жодного розміру, який підходить для всіх підходів.
ікар

3

З версії 20160422 ви можете:

## Solve in PARALLEL
parallel {1} -m {2} -o {3} --timeout 3600 ::: "${METHODS[@]}" :::+ "${INFILES[@]}" :::+ "${OUTFILES[@]}"

Якщо у вас старіша версія:

## Solve in PARALLEL
parallel --xapply {1} -m {2} -o {3} --timeout 3600 ::: "${METHODS[@]}" ::: "${INFILES[@]}" ::: "${OUTFILES[@]}"

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


Дуже хороша! Я актуалізував своє запитання під час своєї першої спроби паралельно з GNU. Ну, це не дуже елегантно в порівнянні з вашим рішенням, але чи маєте ви уявлення про те, наскільки добре вони будуть виконувати ці рішення? Дуже дякую!
Khue

Моє рішення використовуватиме близько 250 мс + 10 мс на роботу.
Оле Танге

Я щойно перевірив ваше рішення, і він нічого не робить: \
Khue

Я щиро вибачаюсь за те, що поспішив прийняти вашу відповідь. Ваше рішення не вирішує мою основну проблему: багато процесів мають стан D. Я використовую паралельно GNU, а не waitстикаюся з тією ж проблемою.
Khue

Чи можете ви спробувати замість запуску розв’язувача виконати щось, що займає <1 Гб оперативної пам’яті на роботу (наприклад, burnP6)? Якщо це змушує запускати всі процеси, то проблема полягає в тому, що ваша система занадто мала або диск занадто повільний, щоб паралельно запускати стільки рішень, які ви хочете. Рішення: Купіть більшу / швидку машину або паралельно запустіть менше рішень.
Оле Танге
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.