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)
?
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)
?
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.
Mã này có điều kiện chủng tộc. –
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
'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). –
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.
Đ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? –
không kinda này đánh bại các điểm của việc sử dụng một subprocess? – aaronasterling
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
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.
+1 Đây sẽ là giải pháp của tôi. – aaronasterling
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
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. –
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ỳ.
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.
Đố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
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.
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ợ.
Theo Python 3.3, cũng có đối số timeout
cho các chức năng trình trợ giúp chặn trong mô-đun phụ.
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:
liên quan: [subprocess với timeout] (http://stackoverflow.com/q/1191374/4279) – jfs