报警信号无法在无限循环中触发

时间:2014-10-05 04:05:30

标签: python python-2.7

我正在尝试超时一个函数,如果它运行超过3秒(例如)。我正在使用信号和警报,但警报从未触发。我想要一个适用于任何功能的超时机制。作为我面临的问题的一个例子:

import signal

def foobar():
    x = 42
    while x >= 20:
        if x >= 40:
            x = 23
    return x

def handle_alarm(*args):
    print("Alarm raised")
    raise TimeoutException("timeout reached")

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

try:
    print(foobar())
except:
    print("Exception Caught")

运行时,我的程序会永远运行,我的处理程序永远不会运行。知道为什么会这样吗?

顺便说一句,如果我从foobar中删除if语句,那么警报会触发。

1 个答案:

答案 0 :(得分:2)

在我的系统上,使用MacPorts的Mac OS X,我用许多版本的Python测试了你的代码。展示" bug"的唯一版本你发现是2.7。超时工作在2.4,2.5,2.6,3.3和3.4。

现在,为什么会发生这种情况,可以采取哪些措施呢?

我认为这是因为你的foobar()是一个紧密的循环,永远不会产生"控制回Python的主循环。它只是尽可能快地运行,没有做任何有用的工作,但阻止Python处理信号。

有助于理解* nix中的信号通常如何处理。由于很少有库函数是"异步信号安全,"在C信号处理程序中没有多少可以直接完成。 Python需要调用用Python编写的信号处理程序,但它不能直接在它使用C注册的信号处理程序中执行。因此,程序在其信号处理程序中执行的典型操作是设置一些标志表示已收到信号,然后返回。然后,在主循环中,检查该标志(直接或使用"管道"可以在信号处理程序中写入poll() ed或select() ed )。

所以我认为Python主循环很乐意执行你的foobar()函数,并且信号进来,它设置一些内部状态以知道它需要处理该信号,然后它等待{ {1}}结束或失败,至少foobar()调用某些可中断的函数,例如foobar()sleep()

事实上,如果你添加一个睡眠(任何时间)或print()语句到print的循环,你将获得你想要的超时Python 2.7(以及其他版本)。

一般来说,最好在繁忙的循环中进行短暂的睡眠,然后放松一下#34;他们,从而帮助安排可能需要做的其他工作。你不必每次迭代都要睡觉 - 在这种情况下,通过循环每1000次进行一次微小的睡眠就可以正常工作。