在多处理功能上超时装饰器

时间:2011-12-23 13:26:59

标签: python timeout multiprocessing signals

我直接从网上找到的一个例子中获取这个装饰器:

class TimedOutExc(Exception):
    pass


def timeout(timeout):
    def decorate(f):
        def handler(signum, frame):
            raise TimedOutExc()

        def new_f(*args, **kwargs):

            old = signal.signal(signal.SIGALRM, handler)
            signal.alarm(timeout)

            try:
                result = f(*args, **kwargs)
            except TimedOutExc:
                return None
            finally:
                signal.signal(signal.SIGALRM, old)
            signal.alarm(0)
            return result

        new_f.func_name = f.func_name
        return new_f

    return decorate

如果f函数超时,则抛出异常。

嗯,它可以工作,但是当我在多处理函数上使用这个装饰器并因超时而停止时,它不会终止计算中涉及的进程。我怎么能这样做?

我不想启动异常并停止程序。基本上我想要的是当f超时时,让它返回None然后终止所涉及的过程。

2 个答案:

答案 0 :(得分:9)

虽然我同意Aaron回答的要点,但我想详细说明一下。

multiprocessing启动的流程必须在要装饰的函数中停止;我不认为这可以通常从装饰器本身完成(装饰函数是唯一知道它启动了什么计算的实体)。

您可以捕获自定义SIGALARM异常,而不是使装饰函数捕获TimedOutExc,这可能更灵活。那么你的例子将成为:

class TimedOutExc(Exception):
    """
    Raised when a timeout happens
    """

def timeout(timeout):
    """
    Return a decorator that raises a TimedOutExc exception
    after timeout seconds, if the decorated function did not return.
    """

    def decorate(f):

        def handler(signum, frame):
            raise TimedOutExc()

        def new_f(*args, **kwargs):

            old_handler = signal.signal(signal.SIGALRM, handler)
            signal.alarm(timeout)

            result = f(*args, **kwargs)  # f() always returns, in this scheme

            signal.signal(signal.SIGALRM, old_handler)  # Old signal handler is restored
            signal.alarm(0)  # Alarm removed

            return result

        new_f.func_name = f.func_name
        return new_f

    return decorate

@timeout(10)
def function_that_takes_a_long_time():
    try:
        # ... long, parallel calculation ...
    except TimedOutExc:
        # ... Code that shuts down the processes ...
        # ...
        return None  # Or exception raised, which means that the calculation is not complete

答案 1 :(得分:2)

我怀疑可以用装饰器完成:装饰器是函数的包装器;功能是一个黑盒子。装饰器与它包装的功能之间没有通信。

您需要做的是重写函数的代码,以使用SIGALRM处理程序终止它已启动的任何进程。