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
精彩评论