关于python:超时后杀死或终止子进程?

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'])

评论:

  • 在这里,看门狗超时是几秒钟;但通过更改time.sleep()值可以轻松更改为任何需要的内容。 time_out必须相应记录;
  • 根据需要,这里可能更适合提出一些例外。
  • 文档:我在subprocess模块的文档中苦苦挣扎,以了解subprocess.Popen没有阻塞;这个过程是并行执行的(也许我这里没有使用正确的单词,但我认为这是可以理解的)。

    但是正如我所写的那样,它的执行是线性的,我真的必须等待命令完成,并有一个时间以避免命令中的错误暂停每晚执行脚本。


    有点复杂,我添加了一个解决类似问题的答案:捕获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秒发出一次警报信号。