2010-09-17 39 views
18

Có bất kỳ đối số hoặc tùy chọn nào để thiết lập thời gian chờ cho phương thức con của Python.Popen?Hết thời gian xử lý con của Python?

Một cái gì đó như thế này:

subprocess.Popen(['..'], ..., timeout=20)?

+1

liên quan: [subprocess với timeout] (http://stackoverflow.com/q/1191374/4279) – jfs

Trả lời

15

Tôi khuyên bạn nên xem Timer class trong mô-đun luồng. Tôi đã sử dụng nó để thực hiện một thời gian chờ cho một Popen.

Đầu tiên, tạo một callback:

def timeout(p): 
     if p.poll() is None: 
      print 'Error: process taking too long to complete--terminating' 
      p.kill() 

Sau đó mở quá trình:

proc = Popen(...) 

Sau đó tạo một bộ đếm thời gian mà sẽ gọi callback thông qua quá trình này với nó.

t = threading.Timer(10.0, timeout, [proc]) 
    t.start() 
    t.join() 

Một nơi nào đó sau này trong chương trình, bạn có thể muốn thêm dòng:

t.cancel() 

Nếu không, chương trình python sẽ tiếp tục chạy cho đến khi bộ đếm thời gian đã chạy xong.

EDIT: Tôi được thông báo rằng có một điều kiện chủng tộc mà quy trình con p có thể chấm dứt giữa các cuộc gọi p.poll() và p.kill(). Tôi tin rằng mã sau đây có thể khắc phục điều đó:

import errno 

    def timeout(p): 
     if p.poll() is None: 
      try: 
       p.kill() 
       print 'Error: process taking too long to complete--terminating' 
      except OSError as e: 
       if e.errno != errno.ESRCH: 
        raise 

Mặc dù bạn có thể muốn xử lý ngoại lệ để xử lý cụ thể chỉ ngoại lệ cụ thể xảy ra khi quá trình con đã kết thúc bình thường.

+0

Mã này có điều kiện chủng tộc. –

+0

Mike, bạn có thể xây dựng hoặc chỉnh sửa bản sửa lỗi ở trên không? Tôi đã sử dụng mã tương tự nhiều lần, và nếu có một vấn đề, tôi chắc chắn sẽ muốn sửa chữa nó. – dvntehn00bz

+1

'print 'Lỗi: quá trình mất quá nhiều thời gian để hoàn thành - terminating'' có thể chạy ngay cả khi nó là một lời nói dối và quá trình của bạn chấm dứt mà không cần bạn giết nó (bởi vì nó trong khoảnh khắc giữa các cuộc gọi' poll' và 'kill' của bạn). –

8

subprocess.Popen không chặn, do đó bạn có thể làm một cái gì đó như thế này:

import time 

p = subprocess.Popen(['...']) 
time.sleep(20) 
if p.poll() is None: 
    p.kill() 
    print 'timed out' 
else: 
    print p.communicate() 

Nó có một nhược điểm ở chỗ bạn phải luôn luôn chờ đợi ít nhất 20 giây cho nó để kết thúc.

+3

Điều này sẽ đóng băng quá trình này trong 20 giây. Điều đó có được chấp nhận không? –

+3

không kinda này đánh bại các điểm của việc sử dụng một subprocess? – aaronasterling

+0

có vẻ như vậy! Tôi nghĩ rằng đây là một chút bất tiện khi sử dụng tiến trình con. – sultan

2

Thật không may, không có giải pháp như vậy. Tôi quản lý để làm điều này bằng cách sử dụng một bộ đếm thời gian threaded sẽ khởi động cùng với quá trình sẽ giết nó sau khi timeout nhưng tôi đã chạy vào một số vấn đề descriptor tập tin cũ vì quá trình zombie hoặc một số như vậy.

+0

+1 Đây sẽ là giải pháp của tôi. – aaronasterling

+1

Tôi cũng gặp phải vấn đề như vậy với các bộ mô tả tập tin về các quá trình zombie. – sultan

+0

Sultan. Nó sẽ có thể để sửa chữa những người. Tôi đã quản lý để cuối cùng đánh bóng ứng dụng của tôi vào một cái gì đó khả thi nhưng nó không phải là chung chung, đủ để xuất bản. –

2

Không có thời gian rảnh. Tôi đoán, những gì bạn đang tìm kiếm là để giết quá trình phụ sau một thời gian. Vì bạn có thể báo hiệu cho tiến trình con, bạn cũng có thể giết nó.

cách tiếp cận chung để gửi một tín hiệu tới tiến trình con:

proc = subprocess.Popen([command]) 
time.sleep(1) 
print 'signaling child' 
sys.stdout.flush() 
os.kill(proc.pid, signal.SIGUSR1) 

Bạn có thể sử dụng cơ chế này chấm dứt sau một thời gian ra thời kỳ.

+0

Có phải sys.stdout.flush phổ quát() cho tất cả các ứng dụng sử dụng tiến trình con không? – sultan

+2

Điều này khá giống với câu trả lời của Abhishek. Anh ấy đang sử dụng SIGKILL và bạn đang sử dụng SIGUSR1. Nó có cùng một vấn đề. –

+0

Ok cảm ơn các bạn! – sultan

4

Bạn có thể làm

from twisted.internet import reactor, protocol, error, defer 

class DyingProcessProtocol(protocol.ProcessProtocol): 
    def __init__(self, timeout): 
     self.timeout = timeout 

    def connectionMade(self): 
     @defer.inlineCallbacks 
     def killIfAlive(): 
      try: 
       yield self.transport.signalProcess('KILL') 
      except error.ProcessExitedAlready: 
       pass 

     d = reactor.callLater(self.timeout, killIfAlive) 

reactor.spawnProcess(DyingProcessProtocol(20), ...) 

sử dụng quy trình API đồng bộ Twisted của.

0

Đối với Linux, bạn có thể sử dụng tín hiệu. Đây là nền tảng phụ thuộc vì vậy một giải pháp là cần thiết cho Windows. Nó có thể làm việc với Mac mặc dù.

def launch_cmd(cmd, timeout=0): 
    '''Launch an external command 

    It launchs the program redirecting the program's STDIO 
    to a communication pipe, and appends those responses to 
    a list. Waits for the program to exit, then returns the 
    ouput lines. 

    Args: 
     cmd: command Line of the external program to launch 
     time: time to wait for the command to complete, 0 for indefinitely 
    Returns: 
     A list of the response lines from the program  
    ''' 

    import subprocess 
    import signal 

    class Alarm(Exception): 
     pass 

    def alarm_handler(signum, frame): 
     raise Alarm 

    lines = [] 

    if not launch_cmd.init: 
     launch_cmd.init = True 
     signal.signal(signal.SIGALRM, alarm_handler) 

    p = subprocess.Popen(cmd, stdout=subprocess.PIPE) 
    signal.alarm(timeout) # timeout sec 

    try: 
     for line in p.stdout: 
      lines.append(line.rstrip()) 
     p.wait() 
     signal.alarm(0) # disable alarm 
    except: 
     print "launch_cmd taking too long!" 
     p.kill() 

    return lines   
launch_cmd.init = False 
3

Thời gian chờ tự động xử lý con trăn không được tích hợp sẵn, vì vậy bạn sẽ phải tự tạo.

này làm việc cho tôi trên Ubuntu 12.10 chạy python 2.7.3

Đặt điều này trong một tập tin gọi test.py

#!/usr/bin/python 
import subprocess 
import threading 

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

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

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

     if self.is_alive(): 
      self.p.terminate() #if your process needs a kill -9 to make 
           #it go away, use self.p.kill() here instead. 

      self.join() 

RunMyCmd(["sleep", "20"], 3).run_the_process() 

Lưu nó, và chạy nó:

python test.py 

Lệnh sleep 20 mất 20 giây để hoàn tất. Nếu nó không chấm dứt trong 3 giây (nó sẽ không) sau đó quá trình được chấm dứt.

[email protected]:~$ python test.py 
[email protected]:~$ 

Có ba giây giữa khi quá trình này được chạy và nó được chấm dứt.

5
import subprocess, threading 

class Command(object): 
    def __init__(self, cmd): 
     self.cmd = cmd 
     self.process = None 

    def run(self, timeout): 
     def target(): 
      print 'Thread started' 
      self.process = subprocess.Popen(self.cmd, shell=True) 
      self.process.communicate() 
      print 'Thread finished' 

     thread = threading.Thread(target=target) 
     thread.start() 

     thread.join(timeout) 
     if thread.is_alive(): 
      print 'Terminating process' 
      self.process.terminate() 
      thread.join() 
     print self.process.returncode 

command = Command("echo 'Process started'; sleep 2; echo 'Process finished'") 
command.run(timeout=3) 
command.run(timeout=1) 

Sản lượng này sẽ là:

Thread started 
Process started 
Process finished 
Thread finished 
0 
Thread started 
Process started 
Terminating process 
Thread finished 
-15 

nơi nó có thể thấy rằng, trong việc thực hiện đầu tiên, quá trình này đã hoàn thành một cách chính xác (trở về mã 0), trong khi ở một thứ hai quá trình đã bị chấm dứt (mã trả về -15).

Tôi chưa thử nghiệm trong cửa sổ; nhưng, ngoài việc cập nhật lệnh ví dụ, tôi nghĩ rằng nó sẽ làm việc vì tôi đã không tìm thấy trong tài liệu bất cứ điều gì mà nói rằng thread.join hoặc process.terminate không được hỗ trợ.

1

Vâng, https://pypi.python.org/pypi/python-subprocess2 sẽ mở rộng các mô-đun Popen với hai chức năng bổ sung,

Popen.waitUpTo(timeout=seconds) 

này sẽ chờ đến acertain số giây cho quá trình hoàn thành, nếu không trở lại Không

cũng,

Popen.waitOrTerminate 

này sẽ chờ đến một điểm, và sau đó gọi .terminate(), sau đó .kill(), một orthe khác hoặc một số sự kết hợp của cả hai, xem tài liệu cho đầy đủ chi tiết:

http://htmlpreview.github.io/?https://github.com/kata198/python-subprocess2/blob/master/doc/subprocess2.html

Các vấn đề liên quan