开发者

Python: stop execution after a maximum time

I have an IronPython script that execute some exes. I want to stop the execution of the current exe if its runtime exceeds a certain amount of time. How can I do this?

Current function:

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
   开发者_Go百科 return result, execTime


If you don't need CPython-compatible code (it doesn't sound like you do), you could use the .NET facilities for process management, like the System.Diagnostics.Process class. It might be a bit simpler than using os.popen.


This code works for me using python. I am not sure how it will behave on IronPython, hope this helps anyway.

"""
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 ]


Since it's in IronPython, I assume it's running on Windows, so process management might be different from what I know from unix.

From the look of you code, what you want to do is: "read the standard output of the process, kill it if runs too long". To do this properly, you need either non-blocking reads on standard output, a temporary file to read the output of the process from, or two threads of execution.

One thread will read the subprocess output.

The other thread will periodically poll the process to check if it terminated, and if it did not terminate after a time, kill it. If you do not want to poll, you need one additional thread: one to wait() on the subprocess, the other to kill it after a time.

Relevant standard library modules:

  • subprocess: use this instead of popen, it's just better in every respect.
  • sched: a basic scheduler to implement periodic polling and killing in a single thread.
  • threading: high-level threading library. In particular threading.Timer is essential to build the poll-free solution.


Here's how I do it ... it does use subprocess so you'll need to tweak it to use 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} ) 

You can probably avoid the need for an additional thread if you use stderr, stdout directly rather than using communicate, you'd just need to be careful to use non-blocking IO on those handles.


I think you can use Popen.poll in the subprocess module to do what you want. (os.popen is deprecated in 2.6)

http://docs.python.org/library/subprocess.html

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜