4

我有一个服务器脚本,我需要能够干净地关闭它。在测试通常的try..except陈述时,我意识到这Ctrl-C不是通常的方式。通常我会像这样包装长时间运行的任务

try:
    ...
except KeyboardInterrupt:
    #close the script cleanly here

所以任务可以干净地关闭Ctrl-C。我以前从未遇到过任何问题,但不知何故,当我遇到Ctrl-C这个特定脚本运行时,脚本只是退出而没有捕获Ctrl-C.

初始版本是使用Processfrom实现的multiprocessingThread我使用from重写了脚本threading,但同样的问题在那里。我以前用过threading很多次,但我是multiprocessing图书馆的新手。无论哪种方式,我以前从未经历过这种Ctrl-C行为。

通常我总是实现哨兵等以有序的方式关闭Queues和实例,但是这个脚本只是退出而没有任何响应。Thread

最后,我也尝试过signal.SIGINT像这样覆盖

def handler(signal, frame):
    print 'Ctrl+C'

signal.signal(signal.SIGINT, handler)
...

这里Ctrl+C实际上被捕获了,但是处理程序没有执行,它从不打印任何东西。

除了threading/multiprocessing方面,部分脚本还包含C++ SWIG对象。我不知道这是否与它有关。我在 OS X Lion 上运行 Python 2.7.2。

所以,有几个问题:

  1. 这里发生了什么?
  2. 我该如何调试呢?
  3. 为了了解根本原因,我需要学习什么?

请注意:脚本的内部是专有的,所以我不能给出代码示例。然而,我非常愿意接收指针,所以我可以自己调试它。我有足够的经验,能够弄清楚是否有人能指出我正确的方向。

编辑:我开始注释掉导入等,看看是什么导致了奇怪的行为,我把它缩小到一个C++ SWIG库的导入。有什么想法为什么要导入C++ SWIG库“窃取” Ctrl-C?然而,我不是有罪图书馆的作者,我的 SWIG 经验有限,所以真的不知道从哪里开始......

编辑 2:我刚刚在 Windows 机器上尝试了相同的脚本,并且在 Windows 7 中Ctrl-C按预期捕获。我不会真的去打扰 OS X 部分,无论如何脚本都会在 Windows 环境中运行。

4

3 回答 3

4

这可能与 Python 管理线程、信号和 C 调用的方式有关。

简而言之 - Ctrl-C 不能中断 C 调用,因为实现需要 python 线程来处理信号,而不仅仅是任何线程,而是主线程(通常被阻塞,等待其他线程)。

事实上,长时间的操作可以阻塞一切。

考虑一下:

>>> nums = xrange(100000000)
>>> -1 in nums
False (after  ~ 6.6 seconds)
>>>

现在,尝试按 Ctrl-C(不间断!)

>>> nums = xrange(100000000)
>>> -1 in nums
^C^C^C   (nothing happens, long pause)
...
KeyboardInterrupt
>>>

Ctrl-C 不适用于线程程序的原因是主线程经常在不可中断的线程连接或锁定上被阻塞(例如,任何“等待”、“连接”或只是一个普通的空“主”线程,这在后台导致python在任何产生的线程上“加入”)。

尝试插入一个简单的

while True:
    time.sleep(1)

在你的主线程中。

如果您有一个长时间运行的 C 函数,请在 C 级别进行信号处理(愿原力与您同在!)。

这主要基于 David Beazley关于该主题的视频。

于 2012-02-04T18:51:08.420 回答
1

它退出是因为其他东西可能会捕获 KeyboardInterupt,然后引发一些其他异常,或者只是返回 None。您仍然应该获得回溯以帮助调试。您需要捕获 stderr 输出或使用 -i 命令行选项运行脚本,以便查看回溯。此外,添加另一个 except 块以捕获所有其他异常。

如果您怀疑 C++ 函数调用正在捕获 CTRL+C,请尝试捕获它的输出。如果 C 函数没有返回任何内容,那么除了要求作者添加一些异常处理、返回代码等之外,您无能为力。

try:
    #Doing something proprietary  ...
    #catch the function call output
    result = yourCFuncCall()

    #raise an exception if it's not what you expected
    if result is None:
        raise ValueError('Unexpected Result')

except KeyboardInterupt:
    print('Must be a CTRL+C')
    return

except:
    print('Unhandled Exception')
    raise
于 2012-02-04T09:03:29.420 回答
0

atexit怎么样? http://docs.python.org/library/atexit.html#module-atexit

于 2012-02-04T10:11:15.420 回答