【问题标题】:timeout a subprocess使子进程超时
【发布时间】:2011-04-22 01:42:06
【问题描述】:

我意识到这可能与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")

【问题讨论】:

    标签: python subprocess


    【解决方案1】:

    可以,但是有问题。即使在您放弃它之后,该过程仍将继续执行您要求它执行的任何操作。如果你真的希望它停止,你必须在放弃它后向它发送一个信号来杀死它。

    由于您正在生成一个新进程(./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 非常危险,是许多安全问题和神秘行为的根源。

    【讨论】:

    • 感谢您的回复 :) 我正在运行 python 2.5,它没有 pOpen.kill(),并且想知道如何才能杀死子进程。我试过stackoverflow.com/questions/1064335/…,但这似乎不起作用。
    • @user388025 - 这确实是你要做的事情。除了,它是配置,对吧?这意味着它会产生大量子流程,其中一些可能需要一段时间才能消失。为了完成这项工作,您可能需要做一些更复杂的事情,以便这些流程最终拥有自己的流程组。
    • @user388025 - 你的意思是["make", "test"]。永远不要使用shell=True,除非你绝对必须知道你在做什么。是的,这也会产生很多子流程,我编辑了我的答案来回答你的问题。您可能还想尝试发送SIGINTRSIGTERM 信号而不是SIGKILL,以便它有机会尝试清理它产生的子进程。
    • 糟糕,不小心删除了我的评论。我要试试你刚才说的,谢谢你的时间:)
    • @user388025 - 我犯了一个错误。 愚蠢的笑容我应该有self.proc.poll() is not None。而是。
    猜你喜欢
    • 2011-04-13
    • 1970-01-01
    • 1970-01-01
    • 2011-09-27
    • 2016-08-25
    • 1970-01-01
    相关资源
    最近更新 更多