2009-11-08 5 views
0

J'ai un script IronPython qui exécute des exes. Je veux arrêter l'exécution de l'exe actuel si son exécution dépasse un certain laps de temps. Comment puis-je faire ceci?Python: arrête l'exécution après un délai maximum

Fonction actuelle:

def execute(programName): 
    t0 = time.time() 
    #should stop the execution of "programName" 
    #if execution exceeds limit 
    p = os.popen(programName,"r") 
    result = p.readline() 
    p.close() 
    execTime = time.time() - t0 
    return result, execTime 

Répondre

1

Si vous n'avez pas besoin de code CPython compatible (il ne semble pas comme vous le faites), vous pouvez utiliser le .NET facilities pour la gestion des processus, comme la classe System.Diagnostics.Process. Cela peut être un peu plus simple que d'utiliser os.popen.

+0

Voilà comment je l'ai fait - en utilisant le filetage dans .NET –

1

Ce code fonctionne pour moi en utilisant python. Je ne suis pas sûr de savoir comment il se comportera sur IronPython, j'espère que cela aidera quand même.

""" 
Monitors a set of processes execution, and termination 
""" 

import subprocess 
from threading import Thread 
import time 

class ProcessMonitor(Thread): 
    def __init__(self): 
     Thread.__init__(self) 
     self.processList = {} 
     self.running = True 

    def monitor(self, pClass, timeout): 
     self.processList[ pClass ] = (time.time(),0,timeout) 

    def stop(self): 
     running = false 

    def run(self): 
     print time.time() # just for debugging!! 
     while self.running: 
      # sleep for a second 
      time.sleep(10) 
      # go over all processes and update the time 
      for pClass in self.processList: 
       currentTime = time.time() 
       # if the process didn't terminate yet 
       if pClass.poll() == None: 
        # check if needs to be terminated! 
        (time_,overall,timeout)=self.processList[pClass] 
        overall = overall + (currentTime-time_) 
        print "%f seconds passed from running of process %d"%(overall,pClass.pid) 
        if overall > timeout: 
         pClass.kill() 
         del self.processList[ pClass] 
        else: 
         self.processList[pClass] = (currentTime,overall,timeout) 
       else: 
        del self.processList[ pClass ] 
+0

Le sous-processus n'est pas pris en charge par IronPython. Je vais essayer d'adapter votre code et voir si je peux résoudre mon problème –

1

Comme il est en IronPython, je suppose qu'il fonctionne sous Windows, si la gestion des processus peut être différent de ce que je sais de unix. De l'apparence de votre code, ce que vous voulez faire est: "lisez la sortie standard du processus, tuez-le si cela dure trop longtemps". Pour ce faire correctement, vous avez besoin de lectures non bloquantes sur la sortie standard, d'un fichier temporaire pour lire la sortie du processus ou de deux threads d'exécution.

Un thread lit la sortie du sous-processus.

L'autre thread interrogera périodiquement le processus pour vérifier s'il s'est terminé et s'il ne s'est pas arrêté après un certain temps, le supprimer. Si vous ne voulez pas interroger, vous avez besoin d'un thread supplémentaire: un à wait() sur le sous-processus, l'autre pour le tuer après un certain temps.

modules de la bibliothèque standard pertinents:

  • subprocess: utiliser ce lieu de popen, il est juste mieux à tous égards.
  • sched: un planificateur de base pour implémenter l'interrogation périodique et la suppression dans un seul thread.
  • threading: bibliothèque de threads de haut niveau. En particulier threading.Timer est essentiel pour construire la solution sans pollutions.
1

Voici comment je le fais ... il utilise un sous-processus donc vous aurez besoin de le modifier pour utiliser popen.

class KillerThread(threading.Thread): 
    def __init__(self, pid, timeout, event): 
    threading.Thread.__init__(self) 
    self.pid = pid 
    self.timeout = timeout 
    self.event = event 
    self.setDaemon(True) 
    def run(self): 
    self.event.wait(self.timeout) 
    if not self.event.isSet() : 
     try: 
     os.kill(self.pid, signal.SIGKILL) 
     except OSError, e: 
     #This is raised if the process has already completed 
     pass 

def runTimed(dt, args, kwargs): 
    event = threading.Event() 
    proc = subprocess.Popen(args, **kwargs) 
    killer = KillerThread(proc.pid, dt, event) 
    killer.start() 

    (stdout, stderr) = proc.communicate() 
    event.set() 
    return (stdout,stderr, proc.returncode) 

#EXAMPLE USAGE - lets it run for at most 3 seconds 
(stdout, stderr, returncode) = \ 
runTimed(3, \ 
    ["path/to/my/executable", "arg1" ] , \ 
    {'stdout':subprocess.PIPE, 'stderr':subprocess.PIPE}) 

Vous pouvez probablement éviter la nécessité d'un fil supplémentaire si vous utilisez stderr, stdout directement plutôt que d'utiliser communiquer, vous auriez juste besoin de faire attention à utiliser IO non-blocage sur les poignées.

Questions connexes