2012-05-24 80 views
2

我搜索了互聯網並學習了其他實現方法 現在我已經發現了這個問題。如果我在subprocess.Popen中寫stdout = subprocess.PIPE,我的執行時間總是會超過 超時。如果我刪除它,然後它正在正常運行時間在超時後終止Python中的子進程

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 

回答

0
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 < 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"]) 
3

你不應該產生一個新的線程,不僅僅是因爲它的時候了5秒鐘,然後使用它的isAlive狀況作爲一個忙等待休息狀態。你不需要額外的線程,你可以在第一個線程中調用時間。

您應該使用延遲(time.sleep)來允許處理器執行一些實際工作,而不是儘可能多地輪詢線程。

而且您應該知道,如果您的進程正在生成大量輸出,則會在進程正在執行時未讀取它並將其填滿管道緩衝區時阻塞。

+0

我搜索互聯網,發現實施它的其他方式。感謝您的答覆。現在我遇到了stdout = subprocess.PIPE的問題。如果我寫它,那麼它正在執行更多的正常執行時間。 – Jack

+0

@KevalVora - 你看起來似乎只有在流程結束後才能讀取管道。如果管道的緩衝區已滿,則子進程將掛起,直到您讀取它或被終止。而使用'time.time'而不是'datetime'會更快。 – mata

+0

我需要運行用戶提交的程序,並檢查是否已成功執行,如果有無限循環,我需要殺死該進程,並且需要向用戶顯示輸出。你能爲此提出任何解決方案嗎? – Jack

0

線程可以在python虛擬機中處理,但不能處理。 所以u必須使用OS的API來殺死UR過程/子進程,諸如(在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) 
+0

我搜索了互聯網,並找到了實現它的其他方式。感謝您的答覆。現在我已更新我的問題,我遇到了stdout = subprocess.pipe的問題。 – Jack