bash: как подождать некоторое время, чтобы избежать одновременного запуска скрипта?

Моя проблема:

Каждую ночь мой crontab запускает несколько ночных тестов на суперкомпьютере, работающем с PBS под CentOS 6.5. При запуске задания ждут в очереди. Когда планировщик разрешает запуск, мои задания начинаются. Довольно часто планировщик запускает все задания точно в одно и то же время (даже если мой crontab запускал их в разные моменты времени).

Я не могу изменить основную часть задания (но я могу добавить что-то раньше). Каждое задание начинается с обновления общего репозитория SVN. Но когда задания запускаются одновременно, у меня возникает ошибка из-за одновременных обновлений в одном и том же репозитории. Я хочу избежать этого.

Что я ожидаю:

При запуске планировщиком задание может ждать несколько секунд перед запуском. Решением может быть ожидание случайного времени перед запуском, но риск того, что одно и то же случайное время будет быстро расти с количеством тестов, которые я выполняю параллельно. Если я уменьшу этот риск, выбрав большое случайное число, мне придется слишком долго ждать (блокируя неиспользуемые ресурсы на суперкомпьютере).

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

Предпочтение отдается решению без MPI.

Конечно, я открыт для других решений. Любая помощь приветствуется.


person Caduchon    schedule 13.11.2017    source источник
comment
Возможно, stackoverflow.com/questions/22427859/ достаточно похоже, чтобы помочь?   -  person Nic3500    schedule 13.11.2017


Ответы (2)


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

{
    flock -s 200
    # your script/code here
} 200> /var/lock/myscript

Имя файла блокировки на самом деле не имеет значения, если у вас есть разрешение на запись для его открытия. Когда эта оболочка запускается, она сначала пытается получить монопольную блокировку /var/lock/myscript. Если другой скрипт уже имеет блокировку, он будет блокироваться до тех пор, пока блокировка не станет доступной.

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

person chepner    schedule 13.11.2017
comment
Если я хорошо понимаю, это будет блокироваться на протяжении всего скрипта. Я просто хочу заблокировать в течение первых секунд выполнения скрипта. - person Caduchon; 13.11.2017
comment
Хм. Может быть, использовать блокировку для сериализации вызовов sleep 1? Затем каждое задание номинально спит в течение 1 секунды, но должно ждать, пока все предыдущие задания в очереди завершат их 1-секундный сон. По сути, nth задание приостанавливается на n секунды, и вам не нужно вручную назначать разное время ожидания для каждого задания. - person chepner; 13.11.2017

Вот решение с использованием GNU parallel

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

Вы можете наблюдать желаемый эффект этой команды, используя этот пример

seq 1 5 | parallel -j1 -k 'echo {}; sleep 1'

-j1 устанавливает максимальное количество одновременно выполняемых заданий равным 1, а -k сохраняет порядок.

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

cat file | parallel -j1 -k bash {}
person etopylight    schedule 13.11.2017