2010-11-11 79 views
16

我想盡可能快地重複執行一個子進程。但是,有時這個過程需要很長時間,所以我想殺死它。 我用signal.signal(...)象下面這樣:超時時殺死或終止子進程?

ppid=pipeexe.pid 
signal.signal(signal.SIGALRM, stop_handler) 

signal.alarm(1) 
..... 
def stop_handler(signal, frame): 
    print 'Stop test'+testdir+'for time out' 
    if(pipeexe.poll()==None and hasattr(signal, "SIGKILL")): 
     os.kill(ppid, signal.SIGKILL) 
     return False 

但有時這些代碼會試圖停止執行下一輪。 停止測試/ home/lu/workspace/152/treefit/test2超時 /bin/sh:/ home/lu/workspace/153/squib_driver:找不到---這是下一次執行;該程序錯誤地停止它。

有誰知道如何解決這個問題?我想在時間停止不執行1秒的時間。睡眠(n)經常等待n秒。我不希望我希望它可以執行少於1秒

+0

所以基本上如果子進程運行超過1秒,你想殺了它並開始下一個?它是否正確? – 2010-11-11 20:06:28

+0

你如何創建你的子過程?因爲它看起來像表達式__ pid = pipeexe.pid__正在獲取將要運行的下一個子進程! – mouad 2010-11-11 21:03:33

+0

所以基本上如果子進程運行超過1秒,你想殺了它並開始下一個?它是否正確?是的,這是正確的 – user504909 2010-11-11 23:31:53

回答

35

你可以做這樣的事情:

import subprocess as sub 
import threading 

class RunCmd(threading.Thread): 
    def __init__(self, cmd, timeout): 
     threading.Thread.__init__(self) 
     self.cmd = cmd 
     self.timeout = timeout 

    def run(self): 
     self.p = sub.Popen(self.cmd) 
     self.p.wait() 

    def Run(self): 
     self.start() 
     self.join(self.timeout) 

     if self.is_alive(): 
      self.p.terminate()  #use self.p.kill() if process needs a kill -9 
      self.join() 

RunCmd(["./someProg", "arg1"], 60).Run() 

的想法是,你創建一個運行命令一個線程,並殺死它,如果超時超過某個合適的值,在這種情況下60秒。

+1

+1。這個方法就是我在構建系統中用於測試可執行文件的東西。 – Macke 2011-06-01 09:53:07

+5

也+1。這似乎是迄今爲止我見過的最乾淨的方法之一。通過使用os.kill(self.p.pid,signal.SIGKILL)(或SIGTERM後跟SIGKILL),也可以在Linux上對Python <2.6進行微小的修改。也可以用self.out,self.err = self.p.communicate()替換self.p.wait(),以避免在填充stdout/stderr管道時阻塞子進程 – FredL 2012-10-31 10:05:23

+0

我粘貼了此代碼,並且我的命令顯示爲正確啓動 - 但是,我需要一次運行一個線程。開始一個過程,讓它自然完成,或者如果花費太長時間就殺了它,然後重新開始。 – 2016-06-24 22:29:23

0

我想這是面向事件編程中使用線程和進程的常見同步問題。

如果您應始終只有一個子進程在運行,請確保當前子進程在運行下一個子進程之前被終止。否則,信號處理程序可能會獲得對最後一個子進程運行的引用,並忽略較早的子進程。

假設子流程A正在運行。在報警信號處理之前,子過程B啓動。緊接着,你的報警信號處理程序試圖殺死一個子進程。由於當前PID(或當前子流程管道對象)在啓動子進程時被設置爲B,因此B被殺死並且A繼續運行。

我的猜測是否正確?

爲了讓您的代碼更易於理解,我將包含在殺死當前子進程的部分之後創建新子進程的部分。這將清楚表明只有一個子進程在任何時間運行。信號處理程序可以執行子進程查殺和啓動,就好像它是循環運行的迭代塊一樣,在這種情況下,每隔1秒用事件驅動報警信號。

2

這是我寫的一個子進程執行的看門狗。我用它現在很多,但我不這麼有經驗,所以也許有一些缺陷在裏面:

import subprocess 
import time 

def subprocess_execute(command, time_out=60): 
    """executing the command with a watchdog""" 

    # launching the command 
    c = subprocess.Popen(command) 

    # now waiting for the command to complete 
    t = 0 
    while t < time_out and c.poll() is None: 
     time.sleep(1) # (comment 1) 
     t += 1 

    # there are two possibilities for the while to have stopped: 
    if c.poll() is None: 
     # in the case the process did not complete, we kill it 
     c.terminate() 
     # and fill the return code with some error value 
     returncode = -1 # (comment 2) 

    else:     
     # in the case the process completed normally 
     returncode = c.poll() 

    return returncode 

用法:

return = subprocess_execute(['java', '-jar', 'some.jar']) 

評論:

  1. 在這裏,看門狗超時在幾秒鐘內;但通過更改time.sleep()值可以輕鬆更改爲任何需要的值。 time_out必須相應記錄;
  2. 根據需要,這裏可能更適合提出一些例外。

文檔:我努力了一下subprocess模塊的文檔,明白subprocess.Popen沒有被阻塞;這個過程是並行執行的(也許我在這裏沒有使用正確的單詞,但我認爲這是可以理解的)。

但是,由於我寫的代碼在執行時是線性的,所以我必須等待命令完成,然後暫停以避免命令中的錯誤暫停腳本的夜間執行。

0

下面是我用什麼:

class KillerThread(threading.Thread): 
    def __init__(self, pid, timeout, event): 
    threading.Thread.__init__(self) 
    self.pid = pid 
    self.timeout = timeout 
    self.event = event 
    self.setDaemon(True) 
    def run(self): 
    self.event.wait(self.timeout) 
    if not self.event.isSet() : 
     try: 
     os.kill(self.pid, signal.SIGKILL) 
     except OSError, e: 
     #This is raised if the process has already completed 
     pass  

def runTimed(dt, dir, args, kwargs): 
    event = threading.Event() 
    cwd = os.getcwd() 
    os.chdir(dir) 
    proc = subprocess.Popen(args, **kwargs) 
    os.chdir(cwd) 
    killer = KillerThread(proc.pid, dt, event) 
    killer.start() 

    (stdout, stderr) = proc.communicate() 
    event.set()  

    return (stdout,stderr, proc.returncode) 
0

複雜一點,我添加了一個answer to solve a similar problem:捕獲標準輸出,飼養標準輸入,並能閒置和/或之後的一些總體運行一段時間後終止。