超时子进程

时间:2010-10-06 21:05:20

标签: python subprocess

我意识到这可能与Using module 'subprocess' with timeout重复。如果是的话,我道歉,只想澄清一些事情。

我正在创建一个子进程,我想运行一段时间,如果它在那段时间内没有完成,我希望它抛出一个错误。以下代码中的某些内容是否有效,或者我们是否必须使用其他问题中回答的信号?在此先感谢!:

def run(self):
    self.runTestCmd()
    self.waitTestComplete(self.timeout)

def runTestCmd(self):
    self.proc = subprocess.Popen("./configure", shell=True)

def waitTestComplete(self, timeout):
    st = time.time() 
    while (time.time()-st) < timeout:
        if self.proc.poll() == 0:
            return True
        else:
            time.sleep(2)
    raise TestError("timed out waiting for test to complete")

1 个答案:

答案 0 :(得分:6)

会的,但它有问题。即使在你放弃之后,这个过程仍将继续做你要求它做的事情。如果你真的希望它停止,你必须发出一个信号来杀死它,如果你真的希望它停止它。

由于您正在生成一个新进程(./configure,这可能是一个配置脚本),而这反过来会创建大量的子进程,这将会变得更加复杂。

import os

def runTestCmd(self):
    self.proc = subprocess.Popen(["./configure"], shell=False,
                                 preexec_fn=os.setsid)

然后os.kill(-process.pid, signal.SIGKILL)应该杀死所有子进程。基本上你正在做的是使用preexec_fn使你的新子进程acquire it's own session group。然后,您将向该会话组中的所有进程发送信号。

产生子进程的许多进程都知道它们需要在它们死之前清理它们的子进程。如果可以的话,你应该尝试对他们好。首先尝试os.signal(-process.pid, signal.SIGTERM),等待一两秒钟让流程退出,然后尝试SIGKILL。像这样:

import time, os, errno, signal

def waitTestComplete(self, timeout):
    st = time.time() 
    while (time.time()-st) < timeout:
        if self.proc.poll() is not None:  # 0 just means successful exit
            # Only return True if process exited successfully,
            # otherwise return False.
            return self.proc.returncode == 0
        else:
            time.sleep(2)
    # The process may exit between the time we check and the
    # time we send the signal.
    try:
        os.kill(-self.proc.pid, signal.SIGTERM)
    except OSError, e:
        if e.errno != errno.ESRCH:
            # If it's not because the process no longer exists,
            # something weird is wrong.
            raise
    time.sleep(1)
    if self.proc.poll() is None: # Still hasn't exited.
        try:
            os.kill(-self.proc.pid, signal.SIGKILL)
        except OSError, e:
            if e.errno != errno.ESRCH:
                raise
    raise TestError("timed out waiting for test to complete")

作为旁注,永远不会使用shell=True,除非您绝对确定这是您想要的。认真。 shell=True是彻头彻尾的危险,是许多安全问题和神秘行为的根源。