多个子进程超时
Posted
技术标签:
【中文标题】多个子进程超时【英文标题】:Multiple subprocesses with timeouts 【发布时间】:2011-09-27 01:27:45 【问题描述】:我正在使用一个依赖 SIGALRM 来设置警报中断的配方—— Using module 'subprocess' with timeout
问题是我有多个 Python 脚本使用 signal.ALARM 进程来设置超时,并且只调用最新的警报。有什么好的方法可以改善这种设置超时的多个 Python 函数?
【问题讨论】:
【参考方案1】:除了简单、快速的 hack,避免使用 SIGALRM。这是一种非常古老、有限的机制,不适合更复杂的事情:您只能设置一个警报,并且它会在当时中断任何系统调用,而不仅仅是您打算中断的系统调用。
使用超时线程杀死进程要干净得多,例如:
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()
根据您要超时的内容,您可能希望使用比 SIGKILL 更轻的信号,以允许超时进程自行清理。
【讨论】:
以上是关于多个子进程超时的主要内容,如果未能解决你的问题,请参考以下文章