2010-10-06 9 views
6

Ich weiß, dass dies ein Duplikat von Using module 'subprocess' with timeout sein könnte. Wenn es so ist, entschuldige ich mich, wollte nur etwas klären.Timeout ein Subprozess

Ich erstelle einen Subprozess, den ich für eine bestimmte Zeit ausführen möchte, und wenn es nicht innerhalb dieser Zeit abgeschlossen ist, möchte ich, dass es einen Fehler auslöst. Würde etwas in der Form des folgenden Codes funktionieren oder müssen wir ein Signal verwenden, wie es in der anderen Frage beantwortet wurde? Vielen Dank im Voraus !:

def run(self): 
    self.runTestCmd() 
    self.waitTestComplete(self.timeout) 

def runTestCmd(self): 
    self.proc = subprocess.Popen("./configure", shell=True) 

def waitTestComplete(self, timeout): 
    st = time.time() 
    while (time.time()-st) < timeout: 
     if self.proc.poll() == 0: 
      return True 
     else: 
      time.sleep(2) 
    raise TestError("timed out waiting for test to complete") 

Antwort

6

Es wäre, aber es hat ein Problem. Der Prozess wird weiterhin tun, was immer Sie wollten, auch nachdem Sie es aufgegeben haben. Sie müssen dem Prozess ein Signal senden, um es zu töten, sobald Sie es aufgegeben haben, wenn Sie wirklich wollen, dass es aufhört.

Da Sie einen neuen Prozess erzeugen (./configure, der vermutlich ein Konfigurationsskript ist), der wiederum eine ganze Tonne von Teilprozessen erzeugt, wird dies ein wenig komplexer werden.

import os 

def runTestCmd(self): 
    self.proc = subprocess.Popen(["./configure"], shell=False, 
           preexec_fn=os.setsid) 

Dann os.kill(-process.pid, signal.SIGKILL) sollten alle Teilprozesse töten. Grundsätzlich verwenden Sie die preexec_fn, um Ihren neuen Unterprozess zu acquire it's own session group zu verursachen. Dann senden Sie ein Signal an alle Prozesse in dieser Session-Gruppe.

Viele Prozesse, die Subprozesse generieren, wissen, dass sie ihre Subprozesse aufräumen müssen, bevor sie absterben. Also solltest du versuchen, nett zu ihnen zu sein, wenn du kannst. Versuchen Sie zuerst os.signal(-process.pid, signal.SIGTERM), warten Sie ein oder zwei Sekunden, bis der Prozess beendet ist, und versuchen Sie dann SIGKILL. Etwas wie folgt aus:

import time, os, errno, signal 

def waitTestComplete(self, timeout): 
    st = time.time() 
    while (time.time()-st) < timeout: 
     if self.proc.poll() is not None: # 0 just means successful exit 
      # Only return True if process exited successfully, 
      # otherwise return False. 
      return self.proc.returncode == 0 
     else: 
      time.sleep(2) 
    # The process may exit between the time we check and the 
    # time we send the signal. 
    try: 
     os.kill(-self.proc.pid, signal.SIGTERM) 
    except OSError, e: 
     if e.errno != errno.ESRCH: 
      # If it's not because the process no longer exists, 
      # something weird is wrong. 
      raise 
    time.sleep(1) 
    if self.proc.poll() is None: # Still hasn't exited. 
     try: 
      os.kill(-self.proc.pid, signal.SIGKILL) 
     except OSError, e: 
      if e.errno != errno.ESRCH: 
       raise 
    raise TestError("timed out waiting for test to complete") 

Als Randbemerkung, nie, nie shell=True verwenden, wenn Sie für absolute Sicherheit wissen, dass das, was Sie wollen. Ernst. shell=True ist geradezu gefährlich und die Quelle vieler Sicherheitsprobleme und mysteriösen Verhaltens.

+0

Vielen Dank für Ihre Antwort :) Ich habe Python 2.5 obwohl, die nicht popen.kill(), und fragte mich, wie ich über den Unterprozess töten könnte. Ich versuchte http://stackoverflow.com/questions/1064335/in-python-2-5-how-do-i-kill-a-subprocess, aber das scheint nicht zu funktionieren. – iman453

+1

@ user388025 - Das ist in der Tat, wie Sie es tun würden. Außer, es ist konfiguriert, oder? Das bedeutet, dass es eine Menge von Teilprozessen hervorbringt, und einige davon können eine Weile dauern, bis sie absterben. Um dies zu tun, müssen Sie möglicherweise etwas viel komplizierteres tun, so dass diese Prozesse mit einer eigenen Prozessgruppe enden. – Omnifarious

+1

@ user388025 - Sie meinen '[" make "," test "]'. Verwenden Sie niemals 'shell = True', es sei denn, Sie müssen unbedingt und wissen, worum es geht. Und ja, das wird auch viele Subprozesse hervorbringen, und ich habe meine Antwort bearbeitet, um deine Frage zu beantworten. Sie können auch versuchen, die Signale 'SIGINTR' oder' SIGTERM' anstelle von 'SIGKILL' zu senden, damit die Subprozesse, die sie hervorbringt, bereinigt werden können. – Omnifarious