2010-10-06 69 views
6

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

回答

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是彻头彻尾的危险和许多安全问题和神秘行为的来源。

+0

感谢您的回复:)我正在运行python 2.5,但它没有pOpen.kill(),并想知道如何才能杀死子进程。我尝试http://stackoverflow.com/questions/1064335/in-python-2-5-how-do-i-kill-a-subprocess但这似乎并没有工作。 – iman453 2010-10-06 21:33:28

+1

@ user388025 - 这确实是你如何去做的。除了它的配置,对吗?这意味着它会产生大量的子流程,其中一些流程可能需要一段时间才能消亡。为了完成这项工作,您可能需要做更复杂的事情,以便这些流程最终拥有自己的流程组。 – Omnifarious 2010-10-06 22:03:25

+1

@ user388025 - 你的意思是'[“make”,“test”]'。除非你绝对必须知道你在做什么,否则不要使用'shell = True'。是的,这也会产生很多子流程,我编辑了我的答案来回答你的问题。您可能还想尝试发送SIGINTR或SIGTERM信号而不是SIGKILL,因此它有机会尝试清除其产生的子进程。 – Omnifarious 2010-10-06 22:14:06