允许Ctrl-C中断一个Python C扩展

我在(自制的)基于C的python扩展中运行一些计算量大的模拟。 偶尔我得到错误的东西,并希望终止一个模拟。 但是,Ctrl-C似乎没有任何效果(除了将^C打印到屏幕上,所以我必须使用kill或系统监视器来终止进程。

据我所见python只是等待C扩展完成,并没有真正与它沟通在这段时间。

有没有办法做到这一点?

Solutions Collecting From Web of "允许Ctrl-C中断一个Python C扩展"

我会重新设计C扩展,以便它们不会长时间运行。

所以,把它们分成更基本的步骤(每个步骤都要运行一段很短的时间,例如10到50毫秒),然后用Python代码来调用这些更基本的步骤。

作为一种编程风格, 延续传球的风格可能与理解有关。

Python在SIGINT上安装了一个信号处理程序,它简单地设置了一个由主解释器循环检查的标志。 为了使这个处理程序正常工作,Python解释器必须运行Python代码。

你有几个选项可供你使用:

  1. 使用Py_BEGIN_ALLOW_THREADS / Py_END_ALLOW_THREADS释放你的C扩展代码的GIL。 不保留GIL时不能使用任何Python函数,但Python代码(和其他C代码)可能与C线程(真正的多线程)同时运行。 一个单独的Python线程可以和C扩展一起执行并捕获Ctrl + C信号。
  2. 设置您自己的SIGINT处理程序并调用原始(Python)信号处理程序。 然后,您的SIGINT处理程序可以执行任何需要的操作来取消C扩展代码并将控制返回给Python解释器。

但是,Ctrl-C似乎没有任何作用

shell中的Ctrl-CSIGINT发送到前台进程组 。 python接收到的信号在C代码中设置了一个标志。 如果你的C扩展在主线程中运行,那么没有Python信号处理程序将被运行(因此你不会在Ctrl-C上看到KeyboardInterrupt异常),除非你调用PyErr_CheckSignals()来检查标志(这意味着:它不应该减慢你的速度),并在需要时运行Python信号处理程序,或者如果你的模拟允许Python代码执行(例如,如果模拟使用Python回调)。 如果扩展在后台线程中运行,那么释放GIL就足以让Python代码在主线程中运行,从而使信号处理程序能够运行。

相关: Cython,Python和KeybordInterrupt入门