2009-08-31 10 views
15

Ho bisogno di fare quanto segue in Python. Voglio generare un processo (sottoprocesso modulo?), E:Python: Esegui un processo e lo uccide se non termina entro un'ora

  • se il processo termina normalmente, per continuare esattamente dal momento in cui termina;
  • se, in caso contrario, il processo "si blocca" e non termina entro (diciamo) un'ora, per ucciderlo e continuare (eventualmente dandogli un altro tentativo, in un ciclo).

Qual è il modo più elegante per realizzare questo?

risposta

20

Il modulo subprocess sarà tuo amico. Avviare il processo per ottenere un oggetto Popen, quindi passarlo a una funzione come questa. Si noti che questo solleva solo un'eccezione al timeout. Se lo si desidera, è possibile rilevare l'eccezione e chiamare il metodo kill() nel processo Popen. (Kill è nuovo in Python 2.6, btw)

import time 

def wait_timeout(proc, seconds): 
    """Wait for a process to finish, or raise exception after timeout""" 
    start = time.time() 
    end = start + seconds 
    interval = min(seconds/1000.0, .25) 

    while True: 
     result = proc.poll() 
     if result is not None: 
      return result 
     if time.time() >= end: 
      raise RuntimeError("Process timed out") 
     time.sleep(interval) 
8

ci sono almeno 2 modi per farlo utilizzando psutil fino a quando si conosce il PID di processo. Supponendo che il processo è stato creato come tale:

import subprocess 
subp = subprocess.Popen(['progname']) 

... si può ottenere la sua data di creazione in un ciclo occupato come questo:

import psutil, time 

TIMEOUT = 60 * 60 # 1 hour 

p = psutil.Process(subp.pid) 
while 1: 
    if (time.time() - p.create_time) > TIMEOUT: 
     p.kill() 
     raise RuntimeError('timeout') 
    time.sleep(5) 

... o più semplicemente, si può fare questo:

import psutil 

p = psutil.Process(subp.pid) 
try 
    p.wait(timeout=60*60) 
except psutil.TimeoutExpired: 
    p.kill() 
    raise 

Inoltre, mentre si è in esso, potreste essere interessati nei seguenti API aggiuntivi:

>>> p.status() 
'running' 
>>> p.is_running() 
True 
>>> 
2

Ho avuto una domanda simile e ho trovato questa risposta. Solo per completezza, voglio aggiungere un altro modo come terminare un processo appeso dopo un certo periodo di tempo: La biblioteca segnale di pitone https://docs.python.org/2/library/signal.html

Dalla documentazione:

import signal, os 

def handler(signum, frame): 
    print 'Signal handler called with signal', signum 
    raise IOError("Couldn't open device!") 

# Set the signal handler and a 5-second alarm 
signal.signal(signal.SIGALRM, handler) 
signal.alarm(5) 

# This open() may hang indefinitely 
fd = os.open('/dev/ttyS0', os.O_RDWR) 

signal.alarm(0)   # Disable the alarm 

Dal momento che si voleva deporre le uova comunque un nuovo processo, questa potrebbe non essere la migliore soluizione per il tuo problema.

1

Un modo piacevole, passivo, è anche utilizzando un threading.Timer e impostazione della funzione di callback.

from threading import Timer 

# execute the command 
p = subprocess.Popen(command) 

# save the proc object - either if you make this onto class (like the example), or 'p' can be global 
self.p == p 

# config and init timer 
# kill_proc is a callback function which can also be added onto class or simply a global 
t = Timer(seconds, self.kill_proc) 

# start timer 
t.start() 

# wait for the test process to return 
rcode = p.wait() 

t.cancel() 

Se il processo termina nel tempo, l'ora() termina e il codice continua qui, annullare() arresta il timer. Se nel frattempo il timer si esaurisce ed esegue kill_proc in un thread separato, wait() continuerà anche qui e cancel() non farà nulla. Con il valore di rcode saprai se abbiamo timeout o no. Più semplice kill_proc: (puoi ovviamente fare qualcosa in più lì)

def kill_proc(self): 
    os.kill(self.p, signal.SIGTERM) 
Problemi correlati