【问题标题】:Alarm signal not firing in infinite loop警报信号未在无限循环中触发
【发布时间】:2014-10-05 04:05:30
【问题描述】:

如果某个函数运行时间超过 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 语句,那么警报就会触发。

【问题讨论】:

  • 可能是一个 python 错误。这在 pypy 下有效。我认为您应该将其提交到错误跟踪器。
  • 你在什么操作系统上运行它?窗户?
  • @Ewan SIGALRM 只存在于 linux 上。

标签: python python-2.7


【解决方案1】:

在我的系统上,带有 MacPorts 的 Mac OS X,我用多个版本的 Python 测试了你的代码。唯一显示您发现的“错误”的版本是 2.7。超时适用于 2.4、2.5、2.6、3.3 和 3.4。

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

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

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

所以我假设 Python 主循环正在愉快地执行您的 foobar() 函数,并且一个信号进来,它设置了一些内部状态以知道它需要处理该信号,然后它等待 foobar()结束或失败,至少foobar() 调用一些可中断的函数,例如sleep()print()

事实上,如果您在foobar() 的循环中添加睡眠(任意时间)或print 语句,您将在 Python 2.7(以及其他版本)。

无论如何,在繁忙的循环中放置一个短暂的睡眠通常是一个好主意,以“放松”它们,从而帮助安排可能需要做的其他工作。您也不必在每次迭代时都睡觉——在这种情况下,只需通过循环每 1000 次进行一次微小的睡眠即可。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    • 1970-01-01
    • 2015-09-28
    相关资源
    最近更新 更多