2015-09-16 3 views
0

Я занимаюсь исследованиями, и мне часто приходится выполнять ту же программу с различными входами (каждая комбинация входов несколько раз) и сохранять результаты для агрегации.Как распределить выполнение над кластером

Я хотел бы ускорить процесс, выполнив эти эксперименты параллельно, на нескольких машинах. Однако я бы хотел избежать проблем с их запуском вручную. Кроме того, я хотел бы, чтобы моя программа была реализована как один поток и только добавила распараллеливание поверх нее.

Я работаю с машинами Ubuntu, доступными в локальной сети. Я знаю, что GNU Parallel может решить эту проблему, но я не знаком с ней. Может ли кто-нибудь помочь мне настроить среду для моих экспериментов?

+0

Без хотя бы контекста этот «вопрос» (на самом деле, ОП опускает вопрос) слишком широк. Что о/с? Как связаны несколько машин (в одной комнате, в одной и той же локальной сети, частях кластера)? Что знает OP о системах управления заданиями (например, Condor, PBS, GNU Parallel? И тогда даже в контексте вопрос, вероятно, требует рекомендации ... –

+0

Идея заключалась в том, чтобы написать учебник, достаточно простой, чтобы другие могли найти. У меня нет блога, поэтому я разместил его здесь. Я не рекламирую Parallel, я просто нашел его полезным для своей работы и хотел разделить плоды пары недель возиться. Неужели это неуместно? – marcotama

ответ

1

Обратите внимание, что этот ответ был адаптирован из одного из моих сценариев и не проверен. Если вы найдете ошибки, вы можете отредактировать ответ.

Прежде всего, чтобы сделать процесс полностью пакетным, нам нужен неинтерактивный вход SSH (это то, что GNU Parallel использует для запуска команд удаленно).

Чтобы сделать это, сначала сгенерировать пару ключей RSA (если у вас еще нет) с:

ssh-keygen -t rsa 

, который будет генерировать пару закрытых и открытых ключей, которые хранятся по умолчанию в ~/.ssh/id_rsa и ~/.ssh/id_rsa.pub. Важно использовать эти места, так как openssh будет искать их здесь. В то время как команды openssh позволяют указать файл закрытого ключа (передавая его по -i PRIVATE_KEY_FILE_PATH), GNU Parallel не имеет такой опции.

Далее, мы должны скопировать открытый ключ на всех удаленных машинах, которые мы будем использовать. Для каждой из машин кластера (я буду называть их «рабочими»), работать на этой команды на локальном компьютере:

ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]_HOST 

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

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

WORKERS_PARALLEL="2/[email protected],[email protected],4/[email protected]" 

Здесь, я указал, что на 192.168.0.10 Я хочу только 2 параллельных процессов, в то время как на 10,0 .111.69 Я хочу. Что касается 192.168.0.20, так как я не указывал ни одного числа, GNU Parallel будет определять, сколько процессоров (на самом деле, ядра ЦП) удаленная машина имеет и выполняет много параллельных процессов.

Так как мне также понадобится тот же список в формате, который openssh может понять, я создам вторую переменную без информации о CPU и пробелы вместо запятых. Я делаю это автоматически с:

WORKERS=`echo $WORKERS_PARALLEL | sed 's/[0-9]*\///g' | sed 's/,/ /g'` 

Теперь пришло время настроить мой код. Я предполагаю, что каждый из рабочих настроен на запуск моего кода, так что мне просто нужно будет скопировать код. На рабочих я обычно работаю в папке/tmp, поэтому следующее следует за этим.Код будет скопирован, хотя на SSH туннель и извлеченный удаленно:

WORKING_DIR=/tmp/myexperiments 
TAR_PATH=/tmp/code.tar.gz 
# Clean from previous executions 
parallel --nonall -S $WORKERS rm -rf $WORKING_DIR $TAR_PATH 
# Copy the the tar.gz file on the worker 
parallel scp LOCAL_TAR_PATH {}:/tmp ::: `echo $WORKERS` 
# Create the working directory on the worker 
parallel --nonall -S $WORKERS mkdir -p $WORKING_DIR 
# Extract the tar file in the working directory 
parallel --nonall -S $WORKERS tar --warning=no-timestamp -xzf $TAR_PATH -C $WORKING_DIR 

Обратите внимание, что несколько казней на той же машине, будут использовать один и тот же рабочий каталог. Я предполагаю, что только одна версия кода будет запущена в определенное время; Если это не так, вам нужно будет изменить команды для использования разных рабочих каталогов. Я использую директиву --warning=no-timestamp, чтобы избежать раздражающих предупреждений, которые могут быть выданы, если время вашего устройства превышает число ваших работников.

Теперь нам нужно создать каталоги на локальной машине для хранения результатов прогонов, по одному для каждой группы экспериментов (т. Е. Нескольких исполнений с теми же параметрами). Здесь я использую два формальные параметры альфа и бета:

GROUP_DIRS="results/alpha=1,beta=1 results/alpha=0.5,beta=1 results/alpha=0.2,beta=0.5" 
N_GROUPS=3 
parallel --header : mkdir -p {DIR} ::: DIR $GROUP_DIRS 

Заметьте здесь, что использование parallel здесь не надо: с помощью цикла работали бы, но я нахожу это более удобный для чтения. Я также сохранил количество групп, которые мы будем использовать на следующем шаге.

Окончательный этап подготовки состоит в создании списка всех комбинаций параметров, которые будут использоваться в экспериментах, каждый раз повторяется столько раз, сколько необходимо. Каждое повторение сочетается с дополнительным числом для идентификации разных прогонов.

ALPHAS="1.0 0.5 0.2" 
BETAS="1.0 1.0 0.5" 
REPETITIONS=1000 
PARAMS_FILE=/tmp/params.txt 
# Create header 
echo REP GROUP_DIR ALPHA BETA > $PARAMS_FILE 
# Populate 
parallel \ 
    --header : \ 
    --xapply \ 
    if [ ! -e {GROUP_DIR}"exp"{REP}".dat" ]';' then echo {REP} {GROUP_DIR} {ALPHA} {BETA} '>>' $PARAMS_FILE ';' fi \ 
    ::: REP $(for i in `seq $REPETITIONS`; do printf $i" %.0s" $(seq $N_GROUPS) ; done) \ 
    ::: GROUP_DIR $GROUP_DIRS \ 
    ::: ALPHA $ALPHAS \ 
    ::: BETA $BETAS 

На этом этапе я также реализовал элемент управления: если файл .dat уже существует, я пропускаю этот набор параметров. Это то, что выходит из практики: я часто прерываю выполнение GNU Parallel, а затем решает возобновить его, повторно выполнив эти команды. С помощью этого простого элемента управления я избегаю больше экспериментов, чем необходимо.

Теперь мы можем, наконец, запустить эксперименты. Алгоритм в этом примере генерирует файл, указанный в параметре --save-data, который я хочу получить. Я также хочу сохранить stdout и stderr в файле для целей отладки.

cat $PARAMS_FILE | parallel \ 
    --sshlogin $WORKERS_PARALLEL \ 
    --workdir $WORKING_DIR \ 
    --return {GROUP_DIR}"exp"{REP}".dat" \ 
    --return {GROUP_DIR}"exp"{REP}".txt" \ 
    --cleanup \ 
    --xapply \ 
    --header 1 \ 
    --colsep " " \ 
    mkdir -p {TEST_DIR} ';' \ 
./myExperiment \ 
    --random-seed {REP} \ 
    --alpha {ALPHA} \ 
    --beta {BETA} \ 
    --save-data {GROUP_DIR}"exp"{REP}".dat" \ 
    '&>' {GROUP_DIR}"exp"{REP}".txt" 

Немного о параметрах. --sshlogin, который может быть сокращен до -S, передает список работников, которые Parallel будет использовать для распространения вычислительной нагрузки. --workdir устанавливает рабочий каталог Parallel, который по умолчанию равен ~. Директивы --return копируют указанный файл после завершения выполнения. --cleanup удаляет файлы, скопированные обратно. --xapply говорит Параллельно интерпретировать параметры как кортежи (а не умножает на декартово произведение). --header 1 сообщает Parallel, что первую строку файла параметров следует интерпретировать как заголовок (записи которого будут использоваться в качестве имен для столбцов). --colsep сообщает Parallel, что столбцы в файле параметров разделены пробелами.

ПРЕДУПРЕЖДЕНИЕ: Версия параллельной версии Ubuntu устарела (2013 год). В частности, есть ошибка, препятствующая правильному запуску вышеуказанного кода, который был исправлен всего несколько дней назад. Чтобы получить последний месячный снимок, бегите (не нужны привилегии суперпользователя):

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash 

Обратите внимание, что исправление для ошибки я упоминал выше, будет включено только в следующем снимке, 22 сентября 2015 года, если вы торопитесь, вы должны выполнить ручную установку курения.

Наконец, это хорошая привычка чистить наши рабочие среды:

rm $PARAMS_FILE 
parallel --nonall -S $WORKERS rm -rf $WORKING_DIR $TAR_PATH 

Если вы используете это для и опубликовать исследовательский документ, не забудьте сослаться на оригинальную работу по Оле Танге (см parallel --bibtex).

Смежные вопросы