【问题标题】:Kill Subprocess in Python after timeout超时后在Python中杀死子进程
【发布时间】:2012-05-30 19:49:55
【问题描述】:

我在网上搜索并学习了其他实现它的方法 现在我发现了这个问题。我的执行时间总是不止于此 如果我在 subprocess.Popen 中写入 stdout=subprocess.PIPE,则超时。如果我要删除它,那么它需要正常的执行时间

import subprocess, datetime, os, time, signal
//setting time for timeout
timeout=3
start = datetime.datetime.now()
process = subprocess.Popen(["python", "/home/bourne/untitled.py"],shell=False, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
while process.poll() is None:
        time.sleep(0.1)
        now = datetime.datetime.now()
        if (now - start).seconds > timeout:
            os.kill(process.pid, signal.SIGKILL)
            os.waitpid(-1, os.WNOHANG)
            print "error"       
            print (now - start).seconds
            break
        print (now - start).seconds

【问题讨论】:

    标签: python multithreading subprocess


    【解决方案1】:

    您不应该仅仅因为它在 5 秒内超时就生成一个新线程,然后使用它的 isAlive 状态作为忙等待的中断条件。你不需要额外的线程,你可以在第一个线程中弄乱时间。

    您应该使用延迟 (time.sleep) 来让处理器做一些真正的工作,而不是尽可能频繁地轮询线程。

    而且你应该知道,如果你的进程产生了大量的输出,如果你在进程执行时不读取它,它会阻塞,让它填满管道的缓冲区。

    【讨论】:

    • 我搜索了互联网并找到了其他实现方式。感谢您的回复。现在我遇到了 stdout=subprocess.PIPE 的问题。如果我写它,那么它需要更多的执行时间,否则正常的执行时间。
    • @KevalVora - 您似乎仍然只有在进程完成后才读取管道。如果管道的缓冲区已满,则子进程将挂起,直到您从中读取或将其杀死。并且使用time.time 而不是datetime 会更快。
    • 我需要运行用户提交的程序并检查它是否已经成功执行,如果有无限循环我需要杀死那个进程,我需要向用户显示输出。您能为此提出任何解决方案吗?
    • 是的,只需在进程运行时读取输出 (stdout/stdin)。 那个是你可以在第二个线程中做的事情。
    【解决方案2】:

    线程可以在 python VM 中处理,但不能处理。 所以你必须使用 OS api 来杀死你的进程/子进程,例如(在 linux 中):

    os.system("kill -9 %s"%(proc.pid))
    

    而且,使用线程进行计时是个坏主意。怎么样:

    start_t = time.time()
    TIME_END, TIME_SLEEP = 5, 1
    while time.time() - start_t < TIME_END:
        if proc.poll():
            break
        time.sleep(TIME_SLEEP)
    

    【讨论】:

    • 我搜索了互联网并找到了其他实现方式。感谢您的回复。现在我已经更新了我的问题,我遇到了 stdout=subprocess.pipe 的问题。
    【解决方案3】:
    I have successfully solved the problem. the solution is 
    
    import subprocess, signal, os, threading, errno
    from contextlib import contextmanager
    
    class TimeoutThread(object):
        def __init__(self, seconds):
            self.seconds = seconds
            self.cond = threading.Condition()
            self.cancelled = False
            self.thread = threading.Thread(target=self._wait)
    
        def run(self):
            """Begin the timeout."""
            self.thread.start()
    
        def _wait(self):
            with self.cond:
                self.cond.wait(self.seconds)
    
                if not self.cancelled:
                    self.timed_out()
    
        def cancel(self):
            """Cancel the timeout, if it hasn't yet occured."""
            with self.cond:
                self.cancelled = True
                self.cond.notify()
            self.thread.join()
    
        def timed_out(self):
            """The timeout has expired."""
            raise NotImplementedError
    
    class KillProcessThread(TimeoutThread):
        def __init__(self, seconds, pid):
            super(KillProcessThread, self).__init__(seconds)
            self.pid = pid
    
        def timed_out(self):
            try:
                os.kill(self.pid, signal.SIGKILL) // this is for linux you need to change it for windows
            except OSError,e:
                # If the process is already gone, ignore the error.
                if e.errno not in (errno.EPERM, errno. ESRCH):
                    raise e
    
    @contextmanager
    def processTimeout(seconds, pid):
        timeout = KillProcessThread(seconds, pid)
        timeout.run()
        try:
            yield
        finally:
            timeout.cancel()
    
    
    def example(cmd):
        proc = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
        //setting the timeout to be 1 sec
        with processTimeout(1, proc.pid):
            stdout,stderr=proc.communicate()       
    
        resultcode = proc.wait()
        if resultcode &lt; 0:
            #print "error: %i" % resultcode
            return resultcode,0
        else:
            return stdout,stderr
    
    
    
    
    
    //This is used to create new subprocess and it will return output as well as error
    output,err=example(["python",filepath,"5"])
    

    【讨论】:

      猜你喜欢
      • 2010-12-08
      • 1970-01-01
      • 1970-01-01
      • 2019-12-09
      • 1970-01-01
      • 2011-07-06
      • 2012-05-03
      • 2016-04-22
      • 2011-05-08
      相关资源
      最近更新 更多