2013-01-18 10 views
6

Powiel możliwe:
Python: single instance of programPrevent działa współbieżnych wystąpień skryptu Pythona

muszę zapobiec crona z prowadzenia jednoczesnych przypadki, gdy praca trwa dłużej, aby zakończyć niż wyrzutni interwał. Próbuję użyć koncepcji flock, aby to osiągnąć, ale moduł fcntl nie zachowuje się tak, jak się spodziewam.

Czy ktoś może mi powiedzieć, dlaczego to działa, aby zapobiec dwóch równoczesnych wystąpień:

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) 

i dlaczego to nie działa:

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 
+1

Możliwa DUP z http://stackoverflow.com/questions/380870/python-single-instance-of-program. Które również wirowało z biblioteki zwanej [tendo] (http://pypi.python.org/pypi/tendo), aby poradzić sobie z wszystkimi irytującymi problemami z wieloma platformami. Oczywiście nie odpowiada na pytanie "Dlaczego działa, ale nie B?" pytanie, ale rozwiązuje podstawowe pytanie "Jak mam to zrobić?" – abarnert

Odpowiedz

6

Moja skromna opinia (chociaż mogę być całkowicie błędna) jest taka, że ​​file_handle jest lokalna dla funkcji (w drugim przypadku) i dlatego zostaje zniszczona po wykonaniu tej funkcji.

Poniższy kod wydaje się działać zgodnie z oczekiwaniami:

#!/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 

Zauważmy, że jedyną rzeczą, którą zrobiłem jest ustawienie file_handle jako zmienną globalną (choć skopiował cały kod, aby mieć przykład roboczy)

+0

Dobry połów. Problem polega na tym, że uchwyt pobiera śmieci zebrane przed zakończeniem działania pierwszej instancji, zwalniając blokadę, nawet jeśli jeszcze się nie zakończyła. Wydaje się, że ma to dobry powód, by z tego skorzystać. Następnie można użyć tego samego kodu, aby uniemożliwić równoczesne działanie wielu dowolnych pętli, wątków lub procesów. Z drugiej strony możesz po prostu spróbować http://stackoverflow.com/questions/2798727/named-semaphores-in-python –

-1

Najprostszym sposobem byłoby utworzyć plik/tmp/scriptlock na początku skryptu i sprawdź, czy plik istnieje przed rozpoczęciem pracy. Upewnij się, że plik blokady został usunięty na końcu przetwarzania.

+0

Jeśli to zrobisz, upewnij się, że korzystasz z modułu tempfile Pythona, aby uniknąć warunków wyścigu. – limscoder

+1

Jest to dokładnie to samo, co program OP, a pytanie, które zadał, brzmi: "dlaczego są różne?". Nie "jak mogę to zrobić?" –

+0

Jestem otwarty na inne sposoby unikania wyścigów, nawet jeśli nie używają fcntl. – tponthieux

0

Jak już wspomniałem w odpowiedzi na moje pytanie w odpowiedzi na @ BorrajaX, ponieważ wygląda na to, że i tak jesteś związany z POSIX, możesz spróbować użyć wersji native named semaphore.

Powiązane problemy