2010-11-11 15 views
16

Tôi muốn thực hiện nhiều lần một tiến trình con càng nhanh càng tốt. Tuy nhiên, đôi khi quá trình này sẽ mất quá nhiều thời gian, vì vậy tôi muốn giết nó. tôi sử dụng signal.signal (...) như dưới đây:Giết hoặc chấm dứt quá trình con khi hết thời gian chờ?

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 

nhưng đôi khi mã này sẽ cố gắng để ngăn chặn các vòng tiếp theo từ thực hiện. Dừng kiểm tra/home/lu/workspace/152/treefit/test2cho thời gian ra /bin/sh:/home/lu/không gian làm việc/153/squib_driver: không tìm thấy --- đây là lần thực hiện tiếp theo; chương trình dừng lại sai.

Có ai biết cách giải quyết vấn đề này không? Tôi muốn dừng lại trong thời gian không thực hiện 1 giây time.sleep (n) thường đợi n giây. Tôi không muốn rằng tôi muốn nó có thể thực hiện ít hơn 1 giây

+0

Vì vậy, về cơ bản nếu quá trình con chạy quá 1 giây, bạn muốn giết nó và bắt đầu bước tiếp theo? Điều này có đúng không? –

+0

Làm cách nào để bạn tạo quy trình con? bởi vì nó trông giống như biểu thức __ppid = pipeexe.pid__ đang nhận tiến trình con tiếp theo sẽ được chạy !!! – mouad

+0

Vì vậy, về cơ bản nếu quá trình con chạy quá 1 giây, bạn muốn giết nó và bắt đầu bước tiếp theo? Điều này có đúng không? vâng, đó là đúng – user504909

Trả lời

35

Bạn có thể làm một cái gì đó như thế này:

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() 

Ý tưởng là bạn tạo một sợi chạy lệnh và giết nó nếu thời gian chờ vượt quá một số giá trị phù hợp, trong trường hợp này là 60 giây.

+1

+1. Phương pháp này là những gì tôi sử dụng trong hệ thống xây dựng của tôi để thử nghiệm các tệp thi hành. – Macke

+5

Ngoài ra +1. Điều này có vẻ là một trong những phương pháp sạch nhất mà tôi đã nhìn thấy cho đến nay. Với sửa đổi nhỏ hoạt động trên Python <2.6 trên Linux cũng sử dụng os.kill (self.p.pid, signal.SIGKILL) (hoặc SIGTERM theo sau bởi SIGKILL). Cũng có thể thay thế self.p.wait() bằng self.out, self.err = self.p.communicate() để tránh chặn tiến trình phụ nếu nó điền vào các ống stdout/stderr – FredL

+0

Tôi đã dán mã này vào và lệnh của tôi xuất hiện được bắt đầu đúng cách - tuy nhiên, tôi cần chạy một luồng tại một thời điểm. Bắt đầu một quá trình, để cho nó kết thúc một cách tự nhiên hoặc giết nó nếu nó mất quá nhiều thời gian, sau đó bắt đầu lại. –

0

Tôi đoán đây là vấn đề đồng bộ hóa phổ biến trong lập trình hướng sự kiện với chủ đề và quy trình.

Nếu bạn luôn luôn chỉ nên chạy một tiến trình con, hãy đảm bảo tiến trình con hiện tại bị hủy trước khi chạy bước tiếp theo. Nếu không, trình xử lý tín hiệu có thể nhận được một tham chiếu đến tiến trình con chạy cuối cùng và bỏ qua cái cũ hơn.

Giả sử tiến trình con A đang chạy. Trước khi tín hiệu cảnh báo được xử lý, tiến trình con B được khởi động. Ngay sau đó, trình xử lý tín hiệu cảnh báo của bạn cố gắng giết một tiến trình con. Khi PID hiện tại (hoặc đối tượng đường ống subprocess hiện tại) được đặt thành B khi khởi chạy tiến trình con, B bị giết và A tiếp tục chạy.

Đoán của tôi có đúng không?

Để làm cho mã của bạn dễ hiểu hơn, tôi sẽ bao gồm phần tạo ra một quy trình con mới ngay sau khi phần giết chết quy trình con hiện tại. Điều đó sẽ làm cho rõ ràng chỉ có một tiến trình con chạy bất cứ lúc nào. Bộ xử lý tín hiệu có thể thực hiện cả quá trình giết chóc và khởi chạy con, như thể nó là khối lặp chạy trong một vòng lặp, trong trường hợp này điều khiển sự kiện với tín hiệu báo động sau mỗi 1 giây.

2

Đây là một cái gì đó tôi đã viết như một cơ quan giám sát để thực hiện quy trình con. Tôi sử dụng nó bây giờ rất nhiều, nhưng tôi không quá giàu kinh nghiệm như vậy có lẽ có một số sai sót trong đó:

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 

Cách sử dụng:

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

Bình luận:

  1. ở đây, cơ quan giám sát thời gian ra là trong vài giây; nhưng thật dễ dàng để thay đổi bất cứ điều gì cần thiết bằng cách thay đổi giá trị time.sleep(). time_out sẽ phải được ghi lại cho phù hợp;
  2. theo những gì cần thiết, ở đây có thể phù hợp hơn để nêu một số ngoại lệ.

Tài liệu: Tôi gặp khó khăn một chút với tài liệu của subprocess mô-đun để hiểu rằng subprocess.Popen không chặn; quá trình này được thực hiện song song (có thể tôi không sử dụng từ đúng ở đây, nhưng tôi nghĩ rằng nó là dễ hiểu).

Nhưng như những gì tôi viết là tuyến tính trong thực thi của nó, tôi thực sự phải chờ lệnh hoàn thành, với một thời gian để tránh lỗi trong lệnh để tạm dừng thực thi hàng đêm của tập lệnh.

0

Đây là những gì tôi sử dụng:

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

Một chút phức tạp hơn, tôi đã thêm một answer to solve a similar problem: Chụp stdout, ăn stdin, và có thể chấm dứt sau một thời gian không hoạt động và/hoặc sau một thời gian chạy tổng thể.