Mar*_*cin 5 python linux garbage-collection signals exception
SIGINT 的默认处理程序会引发 KeyboardInterrupt。但是,如果程序位于 __del__ 方法内(由于正在进行的垃圾收集),则该异常将被忽略,并将以下消息打印到 stderr:
Exception KeyboardInterrupt in <...> ignored
因此,尽管收到了 SIGINT,程序仍继续工作。当然,我可以为 SIGINT 定义自己的处理程序,将全局变量 sigint_received 设置为 True,然后经常在程序中检查该变量的值。但这看起来很难看。
有没有一种优雅可靠的方法来确保python程序在收到SIGINT后被中断?
在深入研究我的解决方案之前,我想在文档中突出显示可怕的红色“警告:”侧边栏(object.__del__强调我的):
由于
__del__()调用方法的环境不稳定,执行期间发生的异常将被忽略,而是打印警告sys.stderr。[...]__del__()方法应该做到维护外部不变量所需的绝对最低限度。
这对我来说意味着任何有可能__del__被交互式用户中断的严重风险的方法都Ctrl-C可能做得太多了。所以我的第一个建议是寻找方法来最小化你的__del__方法,无论它是什么。
或者换句话说:如果你的__del__方法确实做到了“所需的绝对最低限度”,那么中途终止进程怎么能安全呢?
我能找到的唯一解决方案确实是一个自定义信号处理程序......signal.SIGINT但是很多明显的技巧都不起作用:
sys.exitsys.exit从信号处理程序调用只是引发了一个SystemExit异常,该异常被忽略了。Python 的 C API 文档表明 Python 解释器不可能在方法期间引发任何异常__del__:
voidPyErr_WriteUnraisable(PyObject *obj)[调用时...]解释器不可能实际引发异常[...]例如,当方法中发生异常时
__del__()。
您在信号处理程序中设置全局“drop dead”变量的想法仅部分起作用——尽管它更新了变量,但在方法返回之前没有任何机会读取__del__该变量。所以有好几秒钟,他们Ctrl-C似乎什么也没做。
如果您只想“最终”终止进程,这可能就足够了,因为只要方法返回,它就会退出__del__。但是,由于您可能想在不等待的情况下关闭进程(两者SIGINT通常KeyboardInterrupt来自不耐烦的用户),因此这是行不通的。
os.kill由于我找不到一种方法来说服 Python 解释器自杀,所以我的解决方案是让(更有说服力的)操作系统为我做这件事。该信号处理程序用于向其自己的进程 IDos.kill发送更强的信号SIGTERM,导致 Python 解释器本身退出。
def _sigterm_this_process(signum, frame):
    pid = os.getpid()
    os.kill(pid, signal.SIGTERM)
    return
# Elsewhere...
signal.signal(signal.SIGINT, _sigterm_this_process)
一旦设置了自定义信号处理程序,  Ctrl-C就会导致该__del__方法(以及整个程序)立即退出。
| 归档时间: | 
 | 
| 查看次数: | 829 次 | 
| 最近记录: |