2010-11-11 67 views
16

我想尽可能快地重复执行一个子进程。但是,有时这个过程需要很长时间,所以我想杀死它。 我用signal.signal(...)象下面这样:超时时杀死或终止子进程?

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:找不到---这是下一次执行;该程序错误地停止它。

有谁知道如何解决这个问题?我想在时间停止不执行1秒的时间。睡眠(n)经常等待n秒。我不希望我希望它可以执行少于1秒

+0

所以基本上如果子进程运行超过1秒,你想杀了它并开始下一个?它是否正确? – 2010-11-11 20:06:28

+0

你如何创建你的子过程?因为它看起来像表达式__ pid = pipeexe.pid__正在获取将要运行的下一个子进程! – mouad 2010-11-11 21:03:33

+0

所以基本上如果子进程运行超过1秒,你想杀了它并开始下一个?它是否正确?是的,这是正确的 – user504909 2010-11-11 23:31:53

回答

35

你可以做这样的事情:

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

+1。这个方法就是我在构建系统中用于测试可执行文件的东西。 – Macke 2011-06-01 09:53:07

+5

也+1。这似乎是迄今为止我见过的最干净的方法之一。通过使用os.kill(self.p.pid,signal.SIGKILL)(或SIGTERM后跟SIGKILL),也可以在Linux上对Python <2.6进行微小的修改。也可以用self.out,self.err = self.p.communicate()替换self.p.wait(),以避免在填充stdout/stderr管道时阻塞子进程 – FredL 2012-10-31 10:05:23

+0

我粘贴了此代码,并且我的命令显示为正确启动 - 但是,我需要一次运行一个线程。开始一个过程,让它自然完成,或者如果花费太长时间就杀了它,然后重新开始。 – 2016-06-24 22:29:23

0

我想这是面向事件编程中使用线程和进程的常见同步问题。

如果您应始终只有一个子进程在运行,请确保当前子进程在运行下一个子进程之前被终止。否则,信号处理程序可能会获得对最后一个子进程运行的引用,并忽略较早的子进程。

假设子流程A正在运行。在报警信号处理之前,子过程B启动。紧接着,你的报警信号处理程序试图杀死一个子进程。由于当前PID(或当前子流程管道对象)在启动子进程时被设置为B,因此B被杀死并且A继续运行。

我的猜测是否正确?

为了让您的代码更易于理解,我将包含在杀死当前子进程的部分之后创建新子进程的部分。这将清楚表明只有一个子进程在任何时间运行。信号处理程序可以执行子进程查杀和启动,就好像它是循环运行的迭代块一样,在这种情况下,每隔1秒用事件驱动报警信号。

2

这是我写的一个子进程执行的看门狗。我用它现在很多,但我不这么有经验,所以也许有一些缺陷在里面:

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 

用法:

return = subprocess_execute(['java', '-jar', 'some.jar']) 

评论:

  1. 在这里,看门狗超时在几秒钟内;但通过更改time.sleep()值可以轻松更改为任何需要的值。 time_out必须相应记录;
  2. 根据需要,这里可能更适合提出一些例外。

文档:我努力了一下subprocess模块的文档,明白subprocess.Popen没有被阻塞;这个过程是并行执行的(也许我在这里没有使用正确的单词,但我认为这是可以理解的)。

但是,由于我写的代码在执行时是线性的,所以我必须等待命令完成,然后暂停以避免命令中的错误暂停脚本的夜间执行。

0

下面是我用什么:

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) 
0

复杂一点,我添加了一个answer to solve a similar problem:捕获标准输出,饲养标准输入,并能闲置和/或之后的一些总体运行一段时间后终止。