Python:使用Signal.Alarm进行超时异常处理

Python: Timeout Exception Handling with Signal.Alarm

我试图实现一个超时异常处理程序,如果函数调用花费太长时间。

编辑:事实上,我正在使用subprocess编写一个Python脚本,它使用参数调用旧的C ++程序。 我知道程序会不时挂起,不会返回任何内容。 这就是为什么我试图设定时间限制并继续使用不同的参数等进行下一次调用。

我一直在寻找并试图实现它,但它不太有用,所以我希望得到一些帮助。 到目前为止我所拥有的是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#! /usr/bin/env python

import signal

class TimeOutException(Exception):
    def __init__(self, message, errors):
        super(TimeOutException, self).__init__(message)
        self.errors = errors

def signal_handler(signum, frame):
    raise TimeOutException("Timeout!")

signal.signal(signal.SIGALRM, signal_handler)
signal.alarm(3)

try:
    while True:
        pass

except TimeOutException:
    print"Timed out!"

signal.alarm(0)

编辑:我当前收到的错误消息是"TypeError:init()正好3个参数(给定2个)

另外,我想问一个关于except块的基本问题。"TimeOutException除外"下的代码与"异常处理程序"中的代码之间的角色差异是什么? 似乎两者都可以做同样的事情?

任何帮助,将不胜感激。


if a function call is taking too long

我意识到这对于没有经验的开发人员来说可能并不明显,但适用于解决这个问题的方法完全取决于你在这个"忙碌功能"中做了什么,例如:

  • 这是一个沉重的计算?如果是,您使用的是哪个Python解释器? CPython还是PyPy?如果CPython:这个计算只使用Python字节码,还是涉及函数调用外包给编译的机器代码(这可能使Python的全局解释器锁保持相当无法控制的时间)?

  • 这有很多I / O工作吗?如果是,您可以在任意状态下中止此I / O工作吗?或者你需要妥善清理?您使用的是gevent或Twisted等特定框架吗?

编辑:
所以,它看起来你只是产生一个子进程并等待它终止。太棒了,这实际上是实现超时控制的最简单问题之一。 Python(3)提供了相应的功能! :-) 看一下

https://docs.python.org/3/library/subprocess.html#subprocess.call

The timeout argument is passed to Popen.wait(). If the timeout
expires, the child process will be killed and then waited for again.
The TimeoutExpired exception will be re-raised after the child process
has terminated.

EDIT2:

您的示例代码,将其保存到文件并使用Python 3.3执行,至少:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import subprocess


try:
    subprocess.call(['python', '-c', 'print("hello")'], timeout=2)
except subprocess.TimeoutExpired as e:
    print("%s was terminated as of timeout. Its output was:
%s"
% (e.cmd, e.output))


try:
    subprocess.call(['python'], timeout=2)
except subprocess.TimeoutExpired as e:
    print("%s was terminated as of timeout. Its output was:
%s"
% (e.cmd, e.output))

在第一种情况下,子进程立即返回。不会引发超时异常。在第二种情况下,超时到期,您的控制进程(在上面的脚本上运行的进程)将尝试终止子进程。这成功了。之后,引发subprocess.TimeoutExpired并且异常处理程序处理它。对我来说,上面脚本的输出是['python'] was terminated as of timeout. Its output was:
None