2013-01-18 12 views
6

Eventuali duplicati:
Python: single instance of programImpedire l'esecuzione istanze simultanee di uno script python

Ho bisogno di evitare un processo di cron esecuzione istanze simultanee quando un lavoro richiede più tempo per completare rispetto al programma di avvio intervallo. Sto cercando di usare il concetto di flock per raggiungere questo obiettivo, ma il modulo fcntl non si comporta come mi aspetto.

Qualcuno può dirmi perché questo funziona per evitare che due istanze simultanee:

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) 

E perché questo non funziona:

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

Possibile duplicato di http://stackoverflow.com/questions/380870/python-single-instance-of-program. Che ha anche fatto girare una libreria chiamata [tendo] (http://pypi.python.org/pypi/tendo) per gestire tutti i fastidiosi problemi multipiattaforma. Ovviamente non risponde "Perché funziona A ma non B?" domanda, ma risolve la domanda di fondo "Come devo fare questo?" – abarnert

risposta

6

Il mio modesto parere (sebbene possa essere completamente sbagliato) è che file_handle è locale alla funzione (nel secondo caso) e quindi viene distrutto una volta che la funzione è stata completata.

Il seguente codice sembra funzionare come previsto:

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

Si noti che l'unica cosa che ho fatto è la creazione file_handle come variabile globale (anche se ho copiato l'intero codice per avere un esempio di lavoro)

+0

Buona presa. Quindi il problema è che l'handle viene recuperato prima della fine della prima istanza, rilasciando il blocco anche se non è ancora stato completato. Sembra una buona ragione per usare e obiettare per questo. È quindi possibile utilizzare lo stesso codice per impedire che le operazioni vengano eseguite contemporaneamente su qualsiasi numero di cicli, thread o processi. Poi di nuovo, puoi semplicemente provare http://stackoverflow.com/questions/2798727/named-semaphores-in-python –

-1

modo più semplice sarebbe quella di creare un file/tmp/scriptlock all'inizio dello script e controlla se quel file esiste prima di lavorare. Assicurati che il file di blocco venga rimosso anche alla fine dell'elaborazione.

+0

Se lo fai, assicurati di usare il modulo tempfile di Python per evitare le condizioni di gara – limscoder

+1

Questo è molto simile a quello che l'OP sta facendo, e la domanda che ha posto è "perché sono diversi?" Non, "come posso fare questo?" –

+0

Sono aperto ad altri modi per evitare le condizioni di gara anche se non usano fcntl. – tponthieux

0

Come ho accennato nella mia risposta alla risposta di @ BorrajaX, dato che sembra che tu sia legato a POSIX in ogni caso, puoi provare a usare uno native named semaphore.