Ngoại trừ các hacks đơn giản, nhanh chóng, tránh SIGALRM. Đó là một cơ chế rất hạn chế, không phù hợp với bất cứ điều gì phức tạp hơn: bạn chỉ có thể đặt một báo thức duy nhất và nó sẽ ngắt bất kỳ cuộc gọi hệ thống nào vào thời điểm đó thay vì chỉ là lệnh bạn định ngắt.
Đó là sạch hơn để sử dụng một sợi thời gian chờ để giết chết quá trình, ví dụ:
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)
except OSError as 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():
proc = subprocess.Popen(["sleep", "5"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
with processTimeout(1, proc.pid):
print proc.communicate()
resultcode = proc.wait()
if resultcode < 0:
print "error: %i" % resultcode
if __name__ == '__main__':
example()
Tùy thuộc vào những gì bạn đang thời gian ra ngoài, bạn có thể muốn sử dụng một tín hiệu nhẹ hơn SIGKILL để cho phép thời gian -quá trình để tự dọn dẹp.
Nguồn
2011-07-01 22:06:56