Уведомления

Группа в Telegram: @pythonsu

#1 Март 7, 2014 13:57:08

fedorch
От: Москва (чаще всего)
Зарегистрирован: 2014-03-07
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Кроссплатформенная блокировка повторного запуска.

Требуется предотвратить повторный запуск скрипта, когда одна его копия уже выполняется. Хочется простого, кроссплатформенного решения (и желательно без лишних пакетов). Решение, конечно, должно быть устойчивым к краху скрипта и отключению питания ;-) Поиск в сети показал, что большинство программистов думает, что под Windows и Unix это нужно делать по разному (или использовать какой нибудь дополнительный пакет, который прячет эти различия внутри себя).

Немного подумав набросал следующее решение. Мне оно кажется идеальным, но возможно я что-то упустил?

import os
import os.path
import time
 
# Проверяем наличие lock-файл и пытаемся удалить его
if os.path.exists("lock.txt"):
    try:
        os.remove("lock.txt")
    except os.error:
        # если не получилось, то другая копия скрипта
        # ещё работает.
        print("Another copy is already running...")
        exit(1)
 
# Создаем lock-файл и делаем свое дело
with open("lock.txt", "w") as lock:
    while True:
        print(time.time())
        time.sleep(5)

Офлайн

#2 Март 7, 2014 18:22:23

Alen
Зарегистрирован: 2013-08-01
Сообщения: 373
Репутация: +  49  -
Профиль   Отправить e-mail  

Кроссплатформенная блокировка повторного запуска.

fedorch
Мне оно кажется идеальным, но возможно я что-то упустил?

В Linux/MacOS X/BSD работать не будет

Писать ID процесса в файл. При запуске читать файл, проверять наличие процесса с заданным ID, если таковой существует то запуск повторный.

import os
pid = os.getpid()
def check_pid(pid):        
    """ Check for the existence of a pid. """
    try:
        os.kill(pid, 0)
    except OSError:
        return False
    else:
        return True

http://docs.python.org/2/library/os.html

или psutils

Отредактировано Alen (Март 7, 2014 19:04:59)

Офлайн

#3 Март 7, 2014 18:44:43

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

Кроссплатформенная блокировка повторного запуска.

fedorch
но возможно я что-то упустил?
Вы пишете файл в текущей директории, значит можно запустить много процессов меняя текущую директорию.

Чтобы сделать это библиотечной функцией вам надо будет быть поизобретательней с именем файла.

Может не получиться удалить файл просто если на это не хватит прав. (машина упала и вы зашли как другой пользователь).

Если вы уже посмотрели решения неплохо написать какие и почему они вам не подошли.
http://pythonhosted.org/lockfile/lockfile.html
http://twistedmatrix.com/trac/browser/trunk/twisted/python/lockfile.py
http://pypi.python.org/pypi/zc.lockfile

Еще вам вопрос на обдумывание. Если программа зависла, то она считается работающей или нет?

Желание не использовать сторонние библиотеки - это желание увеличить на единицу количество сторонних библиотек.



Отредактировано doza_and (Март 7, 2014 19:16:17)

Офлайн

#4 Март 7, 2014 19:09:55

fedorch
От: Москва (чаще всего)
Зарегистрирован: 2014-03-07
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Кроссплатформенная блокировка повторного запуска.

Alen
Писать ID процесса в файл. При запуске читать файл, проверять наличие процесса с заданным ID, если таковой существует то запуск повторный.
Спасибо за информацию по процессам. Не думал, что часть этих функций кроссплатформенна. Не могли бы вы уточнить, что делает kill с сигналом ноль кроме того, что или вызывает или не вызывает исключение (из документации это непонятно).

Теперь по сути предложения. Допустим наш скрипт рухнул. Файл с идентификатором остался на диске. Есть ли гарантия, что другой процесс не получит этот же идентификатор и испортит нам проверку?

Офлайн

#5 Март 7, 2014 19:14:35

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

Кроссплатформенная блокировка повторного запуска.

fedorch
получит этот же идентификатор
так вы сами посмотрите - пиды четырехзначные. Конечно никто не гарантирует отсутствия повторений.



Офлайн

#6 Март 7, 2014 19:17:03

fedorch
От: Москва (чаще всего)
Зарегистрирован: 2014-03-07
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Кроссплатформенная блокировка повторного запуска.

doza_and
Вы пишете файл в текущей директории, значит можно запустить много процессов меняя текущую директорию.

Чтобы сделать это библиотечной функцией вам надо будет быть поизобретательней с именем файла.

Может не получиться удалить файл просто если на это не хватит прав. (машина упала и вы зашли как другой пользователь).

Спасибо за замечания. Это минимальный рабочий пример. Естественно в релизе путь к файлу будет абсолютный, а лежать он будет там же, где и данные, которые собственно и являются причиной необходимости блокировки. Так что проблем с доступом или пересечением имен ;-) быть не должно.

Я уже оформил это в виде небольшого класса. В конструктор (передаем имя файл для блокировки) и два метода lock() и unlock().

doza_and
Если вы уже посмотрели решения неплохо написать какие и почему они вам не подошли.

Я не искал решение в виде библиотеки. Я искал решение в виде 5-10 строк кода, которые можно добавить в мою программу и добиться этим требуемого результата. И этого я как раз не нашел.

doza_and
Еще вам вопрос на обдумывание. Если программа зависла, то она считается работающей или нет?

Пока, к сожалению, да.

doza_and
Желание не использовать сторонние библиотеки - это желание увеличить на единицу количество сторонних библиотек.

;-) Ну я же не собираюсь переписывать PIL. Но добавлять лишнюю библиотеку (и потом всё время “таскать” её за собой), чтобы сэкономить 10 (ну пусть со всеми проверками 20) строк кода по моему нецелесообразно.

Отредактировано fedorch (Март 7, 2014 19:35:09)

Офлайн

#7 Март 7, 2014 19:26:20

Alen
Зарегистрирован: 2013-08-01
Сообщения: 373
Репутация: +  49  -
Профиль   Отправить e-mail  

Кроссплатформенная блокировка повторного запуска.

fedorch
Не думал, что часть этих функций кроссплатформенна. Не могли бы вы уточнить, что делает kill с сигналом ноль кроме того, что или вызывает или не вызывает исключение (из документации это непонятно).

Собственно только это в Linux/Mac OS X и делает , Windows под рукой нет к сожалению, поэтому не смогу проверить. Если что есть https://code.google.com/p/psutil/

Офлайн

#8 Март 7, 2014 19:54:48

fedorch
От: Москва (чаще всего)
Зарегистрирован: 2014-03-07
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Кроссплатформенная блокировка повторного запуска.

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

Офлайн

#9 Март 7, 2014 20:13:56

Alen
Зарегистрирован: 2013-08-01
Сообщения: 373
Репутация: +  49  -
Профиль   Отправить e-mail  

Кроссплатформенная блокировка повторного запуска.

fedorch
Ну так получается, что даже при 50 процессах одновременно бегущих на компьютере (а в реальности, я думаю, может быть и больше) мы получаем 5% шанс на неверную работу программы и сложно уловимый глюк. Нет - это не наш путь ;-)

PID выдаются последовательно, и циклично начиная от 2 и до 65535, если процесс завершился его PID никому не достанется пока не пробежит весь диапазон, на это могут уйти годы.
Загляните как-нибудь в /var/run

Офлайн

#10 Март 7, 2014 21:24:58

fedorch
От: Москва (чаще всего)
Зарегистрирован: 2014-03-07
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Кроссплатформенная блокировка повторного запуска.

Alen
PID выдаются последовательно, и циклично начиная от 2 и до 65535, если процесс завершился его PID никому не достанется пока не пробежит весь диапазон, на это могут уйти годы.
Посмотрел на три разных компьютера:
1. Мой рабочий ноутбук, Windows XP, uptime 3 дня. Максимальный PID уже 7892
2. Сервер, Debian, uptime месяц. Максимальный PID 21394. Но на нем не бежит ни чего, что активно генерировало новые процессы. Я думаю, что Apache с cgi крутит этот счетчик очень быстро.
3.Сервер, Windows 2003 (контроллер домена), uptime неделя. Максимальный PID 5624.

Соглашусь, что в нормальном режиме работы вероятность коллизий невелика, хотя о годах речь не идет ;-) Но в случае перезагрузки системы вероятность коллизий многократно возрастает. При этом предложенный вами способ имеет только одно потенциальное преимущество перед моим. Он не держит открытым файл в течении всего времени блокировки. Но реально это может вызвать проблемы только при наличии тысяч одновременных блокировок (а мне нужна только 1).

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version