2010-10-27 17 views
6

Desidero utilizzare il sottoprocesso per eseguire un programma, ma è necessario limitare il tempo di esecuzione. Ad esempio, se viene eseguito più di 2 secondi, voglio ucciderlo.Come limitare il tempo di esecuzione del programma quando si utilizza il sottoprocesso?

Per i programmi comuni, kill() funziona correttamente. Ma se provo a eseguire /usr/bin/time something, kill() non può davvero uccidere il programma.

Ma il mio codice di seguito sembra non funzionare bene, il programma è ancora in esecuzione.

import subprocess 
import time 

exec_proc = subprocess.Popen("/usr/bin/time -f \"%e\\n%M\" ./son > /dev/null", stdout = subprocess.PIPE, stderr = subprocess.STDOUT, shell = True) 

max_time = 1 
cur_time = 0.0 
return_code = 0 
while cur_time <= max_time: 
    if exec_proc.poll() != None: 
     return_code = exec_proc.poll() 
     break 
    time.sleep(0.1) 
    cur_time += 0.1 

if cur_time > max_time: 
    exec_proc.kill() 
+0

duplicati con http://stackoverflow.com/questions/1191374/subprocess-with-timeout – starrify

risposta

3

farlo in questo modo nella riga di comando:

perl -e 'alarm shift @ARGV; exec @ARGV' <timeout> <your_command> 

questo verrà eseguito il comando <your_command> e terminare in <timeout> secondo.

un esempio fittizio:

# set time out to 5, so that the command will be killed after 5 second 
command = ['perl', '-e', "'alarm shift @ARGV; exec @ARGV'", "5"] 

command += ["ping", "www.google.com"] 

exec_proc = subprocess.Popen(command) 

oppure è possibile utilizzare il signal.alarm() se lo vuoi con Python, ma è lo stesso.

+6

Rispondendo ad una domanda di Python con il Perl, bello ... –

+0

funziona bene, ma quando provo allarme "perl -e' shift @ARGV; exec @ARGV '3/usr/bin/time ping google.com ", il programma non si fermerà. –

+0

Quindi, come gestire/usr/bin/time some_command? –

9

Se si utilizza Python 2.6 o versione successiva, è possibile utilizzare il modulo multiprocessing.

from multiprocessing import Process 

def f(): 
    # Stuff to run your process here 

p = Process(target=f) 
p.start() 
p.join(timeout) 
if p.is_alive(): 
    p.terminate() 

In realtà, multiprocessing è il modulo sbagliato per questo compito in quanto è solo un modo per controllare quanto a lungo un filo corre. Non hai alcun controllo su eventuali bambini che il thread potrebbe eseguire. Come suggerisce la singolarità, usare signal.alarm è l'approccio normale.

import signal 
import subprocess 

def handle_alarm(signum, frame): 
    # If the alarm is triggered, we're still in the exec_proc.communicate() 
    # call, so use exec_proc.kill() to end the process. 
    frame.f_locals['self'].kill() 

max_time = ... 
stdout = stderr = None 
signal.signal(signal.SIGALRM, handle_alarm) 
exec_proc = subprocess.Popen(['time', 'ping', '-c', '5', 'google.com'], 
          stdin=None, stdout=subprocess.PIPE, 
          stderr=subprocess.STDOUT) 
signal.alarm(max_time) 
try: 
    (stdout, stderr) = exec_proc.communicate() 
except IOError: 
    # process was killed due to exceeding the alarm 
finally: 
    signal.alarm(0) 
# do stuff with stdout/stderr if they're not None 
+0

Grazie, ma non funziona: < –

+0

# Provalo. Dopo 3 secondi, il ping è ancora in esecuzione. importazione sottoprocesso tempo import da multiprocessing importazione processo def f(): exec_proc = subprocess.Popen ("/ usr/bin/tempo di ping google.com", shell = True) p = Process (target = f) p.start() p.join (3) se p.is_alive(): p.terminate() time.sleep (10) –

+0

Hai ragione. 'p.terminate()' uccide solo il thread, non tutti i figli che sono stati generati. Non vedo perché stai usando 'shell = True', quindi aggiornerò la mia risposta con una soluzione usando signal.alarm come suggerisce la singolarità. – jamessan

0

Io uso os.kill(), ma non sono sicuro se funziona su tutti i sistemi operativi.
Segue lo pseudo codice e vedi la pagina Doug Hellman.

proc = subprocess.Popen(['google-chrome'])            
os.kill(proc.pid, signal.SIGUSR1)</code> 
Problemi correlati