Запретить одновременный запуск экземпляров скрипта Python

Возможный дубликат:
Python: единственный экземпляр программы

Мне нужно предотвратить одновременное выполнение задания cron, когда выполнение задания занимает больше времени, чем интервал запуска. Я пытаюсь использовать концепцию flock для достижения этой цели, но модуль fcntl ведет себя не так, как я ожидал.

Может ли кто-нибудь сказать мне, почему это работает для предотвращения двух одновременных экземпляров:

import sys
import time
import fcntl

file_path = '/var/lock/test.py'
file_handle = open(file_path, 'w')

try:
    fcntl.lockf(file_handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
    print 'no other instance is running'
    for i in range(5):
        time.sleep(1)
        print i + 1

except IOError:
    print 'another instance is running exiting now'
    sys.exit(0)

И почему это не работает:

import sys
import time
import fcntl

def file_is_locked(file_path):
    file_handle = open(file_path, 'w')
    try:
        fcntl.lockf(file_handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
        return False
    except IOError:
        return True

file_path = '/var/lock/test.py'

if file_is_locked(file_path):
    print 'another instance is running exiting now'
    sys.exit(0)
else:
    print 'no other instance is running'
    for i in range(5):
        time.sleep(1)
        print i + 1

person tponthieux    schedule 18.01.2013    source источник
comment
Возможное дублирование stackoverflow.com/questions/380870/. Который также создал библиотеку под названием teno для решения всех досадных межплатформенных проблем. Конечно, он не отвечает на вопрос, почему А работает, а Б нет? вопрос, но он решает основной вопрос. Как мне это сделать?   -  person abarnert    schedule 19.01.2013


Ответы (4)


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

Следующий код работает, как ожидалось:

#!/usr/bin/env python
#http://stackoverflow.com/questions/14406562/prevent-running-concurrent-instances-of-a-python-script

import sys
import time
import fcntl

file_handle = None

def file_is_locked(file_path):
    global file_handle 
    file_handle= open(file_path, 'w')
    try:
        fcntl.lockf(file_handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
        return False
    except IOError:
        return True

file_path = '/var/lock/test.py'

if file_is_locked(file_path):
    print 'another instance is running exiting now'
    sys.exit(0)
else:
    print 'no other instance is running'
    for i in range(5):
        time.sleep(1)
        print i + 1

Обратите внимание, что единственное, что я сделал, это установил file_handle как глобальную переменную (хотя я скопировал весь код, чтобы получить рабочий пример)

person BorrajaX    schedule 18.01.2013
comment
Хороший улов. Таким образом, проблема в том, что дескриптор собирает мусор до завершения работы первого экземпляра, таким образом снимая блокировку, даже если она еще не завершена. Похоже, хорошая причина использовать и возражать против этого. Затем вы можете использовать один и тот же код для предотвращения одновременной работы любого количества циклов, потоков или процессов. Опять же, вы можете просто попробовать stackoverflow.com/questions/2798727/ named -семафоры-в-питоне - person Silas Ray; 19.01.2013

Как я уже упоминал в своем комментарии к ответу @ BorrajaX, поскольку похоже, что вы все равно привязаны к POSIX, вы можете попробовать использовать собственный именованный семафор.

person Silas Ray    schedule 18.01.2013

Вместо этого вы можете использовать программу setlock из daemontools Д. Дж. Бернштейна:

http://cr.yp.to/daemontools/setlock.html

person Remy Blank    schedule 18.01.2013

Самый простой способ - создать файл / tmp / scriptlock в начале скрипта и проверить, существует ли этот файл перед выполнением работы. Убедитесь, что файл блокировки удален по окончании обработки.

person Sander Cox    schedule 18.01.2013
comment
Если вы это сделаете, убедитесь, что вы используете модуль Python tempfile, чтобы избежать состояний гонки. - person limscoder; 18.01.2013
comment
Это очень похоже на то, что делает OP, и он задал вопрос: почему они разные? Нет, как я могу это сделать? - person Silas Ray; 18.01.2013
comment
Я открыт для других способов избежать состояний гонки, даже если они не используют fcntl. - person tponthieux; 19.01.2013