具有超时的多个子进程 [英] Multiple subprocesses with timeouts

查看:38
本文介绍了具有超时的多个子进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用一个依赖于SIGALRM的配方来设置警报中断-- Using module 'subprocess' with timeout

问题是我有多个Python脚本使用signal.ALARM进程来设置超时,并且只调用最新的警报。改进此多个Python函数设置超时的好方法是什么?

推荐答案

除了简单、快速的黑客攻击外,请避免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更弱的信号,以允许超时过程自动清除。

这篇关于具有超时的多个子进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆