Я написал bash-скрипт, который делает нечто похожее, истощая локальные ядра процессора. Когда ядро освобождается, оно вызывает новый расчет, пока вычисления не будут завершены. У меня также есть небольшой опыт написания сценариев bash с использованием ssh (для этого требуется ssh-ключ без пароля, если вас устраивает этот риск безопасности). Это личный пример вне контекста, но идея в том, что это bash-скрипт, который динамически зацикливается в зависимости от времени обработки и изменяет параметры. Переменная $ CORES, в вашем случае, должна быть заполнена доступными серверами, и нам нужно найти способ отследить их, чтобы узнать, какой из них вызывать дальше.
Loop () {
# looping function over all runs with the same header, multi-threaded per core.
CMDINIT="$CMD"
for i in "$TREEIN"/"$NAME"*.root # loop over all the existing raw runs of that name
do
# name of the output file and path, eg Tree/30s_production/30s_production-1001.root
OUTPUT=`echo $i | sed "s#$TREEIN/##" |sed "s#$NAME#$TREEOUT/$NAME/$NAME-#" `
INFILE=`echo $i | sed 's$.*/$$'` # name of the input file name, eg 30s_production1001.root
if [ ! -e $OUTPUT ];then # only run if the output file does not exist (won't overwrite existing data)
if [ ! $Cflag ];then # only call the program if we aren't cleaning
echo "Outputting to $OUTPUT..."
RUNNO=`echo $INFILE | sed "s/$NAME//" | sed 's/\..*//'` # get the run number
# there is a way to do this using the Run function? Seems trickier with backgrounding, getting PID, and so on
CMD="$CMDINIT -R $RUNNO"
printf "Executing run with the command:\n\t$CMD\n"
$CMD & PIDS="$PIDS $!" # call run on the run number in background w/o renice
#$CMD & PIDS="$PIDS $!" && sudo renice -n 0 -p $! # call run on the run number in background, renice to -10
while [ `jobs | wc -l` -eq $CORES ] # only run one run command per core
do
jobs > /dev/null # without this the while loop doesn't seem to refresh?
sleep 1 # keep waiting until run is not running on a core
done
fi
else # the output file exists -- should never happen as we check NeedClean first, but anyway, safer
echo "$OUTPUT exists, please run clean!"
exit 1
fi
done
}
Здесь есть две «умные» части (или «хаки», если хотите). Одним из них является цикл while, который проверяет количество jobs
и ждет, пока что-то не освободится. (Мой текущий цикл do основан на одном параметре, но его легко настроить.) Эти jobs
выполняются в скрипте bash, и именно так достигается концепция повторного цикла при условии, что задание завершено; имейте в виду, что это будет идентично, независимо от того, является ли задание локальным или удаленным: команда для вызова команды SSH будет такой же, как и локальное задание (хотя нам может потребоваться собрать все результаты позже со всех серверов или серверы, записывающие данные локально и т. д. по мере необходимости). Другой важный для меня аспект заключается в том, как при вызове $ CMD он также привязывает номер процесса к счетчику с именем $ PIDS. Это позволяет ловушке control_c локального сценария bash иметь возможность уничтожать все дочерние процессы, которые будут включать порожденные процессы на всех ваших 100 серверах, если вы решите прекратить работу раньше; последствия не отслеживания этого ужасны, как вы можете себе представить!
Если вы хотите проверить основной скрипт, он находится здесь: https://github.com/goatface/crabat/blob/master/crabat
Нам нужно изменить определение переменной $ CMD, чтобы она была чем-то порядка
CMD=ssh '$USER@$HOST' /path/to/executable
После этого мы должны динамически привязать флаги к исполняемому файлу для управления различными параметрами (мы также можем отправить их в текстовом файле на каждый сервер через scp, но, в конце концов, нам нужно отслеживать их в любом случае, и для меня это несущественно ). Мой случай устанавливает большинство параметров один раз, но нет никаких причин, по которым мы не можем вызывать это каждый раз, когда открывается сервер. Это выглядит так, где я использую флаги, но это тривиально, чтобы установить буферизацию наборов текстовых файлов с параметрами. Увеличивайте счетную переменную в поле awk для каждого поля по порядку, пока не будет исчерпан и т.д. И сбрасывайте ее в функции Loop каждый раз, когда следующая переменная счетчика увеличивается последовательно через все перестановки параметров.
SetFlags () {
# base command
CMD="./run"
# add options based on final flags
[ $Rflag ] && CMD="$CMD -R $Rval"
[ $Bflag ] && CMD="$CMD -B"
[ $Hflag ] && CMD="$CMD -H $Hval"
[ $Iflag ] && CMD="$CMD -I $Ival"
[ $rflag ] && CMD="$CMD -r"
[ $dflag ] && CMD="$CMD -d"
[ $sflag ] && CMD="$CMD -s"
[ $xflag ] && CMD="$CMD -x"
[ $pflag ] && CMD="$CMD -p"
[ $tflag ] && CMD="$CMD -t"
}
Я включил получение электронных писем по ответам, так как нахожу это интересным вопросом, но мне нужно больше времени, чтобы подумать об отслеживании хостов, когда они освобождаются. Извините, я еще не ответил на весь вопрос!