Kill or terminate subprocess when timeout?
我想尽快重复执行一个子进程。 但是,有时这个过程需要很长时间,所以我想杀掉它。
我使用signal.signal(...)如下所示:
1 2 3 4 5 6 7 8 9 10 | ppid=pipeexe.pid signal.signal(signal.SIGALRM, stop_handler) signal.alarm(1) ..... def stop_handler(signal, frame): print 'Stop test'+testdir+'for time out' if(pipeexe.poll()==None and hasattr(signal,"SIGKILL")): os.kill(ppid, signal.SIGKILL) return False |
但有时这段代码会试图阻止下一轮执行。
停止测试/ home / lu / workspace / 152 / treefit / test2超时
/ bin / sh:/ home / lu / workspace / 153 / squib_driver:not found ---这是下一次执行; 该程序错误地阻止它。
有谁知道如何解决这个问题? 我想及时停止不执行1秒钟.sleep(n)经常等待n秒。 我不希望我希望它可以执行不到1秒
你可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import subprocess as sub import threading class RunCmd(threading.Thread): def __init__(self, cmd, timeout): threading.Thread.__init__(self) self.cmd = cmd self.timeout = timeout def run(self): self.p = sub.Popen(self.cmd) self.p.wait() def Run(self): self.start() self.join(self.timeout) if self.is_alive(): self.p.terminate() #use self.p.kill() if process needs a kill -9 self.join() RunCmd(["./someProg","arg1"], 60).Run() |
我们的想法是创建一个运行该命令的线程,并在超时超过某个合适的值时将其终止,在这种情况下为60秒。
这是我作为子进程执行的监视程序编写的内容。我现在经常使用它,但我不是那么有经验,所以也许它有一些缺陷:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import subprocess import time def subprocess_execute(command, time_out=60): """executing the command with a watchdog""" # launching the command c = subprocess.Popen(command) # now waiting for the command to complete t = 0 while t < time_out and c.poll() is None: time.sleep(1) # (comment 1) t += 1 # there are two possibilities for the while to have stopped: if c.poll() is None: # in the case the process did not complete, we kill it c.terminate() # and fill the return code with some error value returncode = -1 # (comment 2) else: # in the case the process completed normally returncode = c.poll() return returncode |
用法:
1 | return = subprocess_execute(['java', '-jar', 'some.jar']) |
评论:
文档:我在
但是正如我所写的那样,它的执行是线性的,我真的必须等待命令完成,并有一个时间以避免命令中的错误暂停每晚执行脚本。
有点复杂,我添加了一个解决类似问题的答案:捕获stdout,提供stdin,并能够在一段时间不活动后和/或在一些整体运行时之后终止。
这是我使用的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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, dir, args, kwargs ): event = threading.Event() cwd = os.getcwd() os.chdir(dir) proc = subprocess.Popen(args, **kwargs ) os.chdir(cwd) killer = KillerThread(proc.pid, dt, event) killer.start() (stdout, stderr) = proc.communicate() event.set() return (stdout,stderr, proc.returncode) |
我想这是使用线程和进程的面向事件编程中的常见同步问题。
如果您应始终只运行一个子进程,请确保在运行下一个子进程之前终止当前子进程。否则,信号处理程序可能会获得对最后一个子进程运行的引用,并忽略旧的。
假设子进程A正在运行。在处理报警信号之前,启动子过程B.在此之后,您的警报信号处理程序会尝试终止子进程。当启动子进程时,当前PID(或当前子进程管道对象)被设置为B,B被杀死并且A继续运行。
我猜是正确的吗?
为了使代码更容易理解,我将在杀死当前子进程的部分之后包含创建新子进程的部分。这表明在任何时候只有一个子进程在运行。信号处理程序可以执行子进程终止和启动,就像它是循环中运行的迭代块一样,在这种情况下,事件驱动每1秒发出一次警报信号。