首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >忽略Cython、Python和KeyboardInterrupt

忽略Cython、Python和KeyboardInterrupt
EN

Stack Overflow用户
提问于 2013-05-27 17:12:54
回答 4查看 3.8K关注 0票数 14

有没有办法中断(Ctrl+C)基于嵌入在Cython扩展中的循环的Python脚本?

我有以下python脚本:

代码语言:javascript
复制
def main():

    # Intantiate simulator
    sim = PySimulator()
    sim.Run()

if __name__ == "__main__":
    # Try to deal with Ctrl+C to abort the running simulation in terminal
    # (Doesn't work...)
    try:
        sys.exit(main())
    except (KeyboardInterrupt, SystemExit):
        print '\n! Received keyboard interrupt, quitting threads.\n'

这将运行一个循环,该循环是C++ Cython扩展的一部分。然后,在按Ctrl+C键的同时,将抛出KeyboardInterrupt但将其忽略,程序将继续运行,直到模拟结束。

我发现的解决办法是通过捕获SIGINT信号来处理扩展中的异常:

代码语言:javascript
复制
#include <execinfo.h>
#include <signal.h>

static void handler(int sig)
{
  // Catch exceptions
  switch(sig)
  {
    case SIGABRT:
      fputs("Caught SIGABRT: usually caused by an abort() or assert()\n", stderr);
      break;
    case SIGFPE:
      fputs("Caught SIGFPE: arithmetic exception, such as divide by zero\n",
            stderr);
      break;
    case SIGILL:
      fputs("Caught SIGILL: illegal instruction\n", stderr);
      break;
    case SIGINT:
      fputs("Caught SIGINT: interactive attention signal, probably a ctrl+c\n",
            stderr);
      break;
    case SIGSEGV:
      fputs("Caught SIGSEGV: segfault\n", stderr);
      break;
    case SIGTERM:
    default:
      fputs("Caught SIGTERM: a termination request was sent to the program\n",
            stderr);
      break;
  }
  exit(sig);

}

然后:

代码语言:javascript
复制
signal(SIGABRT, handler);
signal(SIGFPE,  handler);
signal(SIGILL,  handler);
signal(SIGINT,  handler);
signal(SIGSEGV, handler);
signal(SIGTERM, handler);

我不能在Python中工作吗,或者至少在Cython中工作吗?当我将要在Windows/MinGW下移植我的扩展时,我希望有一些不太特定于Linux的东西。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-05-28 01:36:13

您必须定期检查挂起的信号,例如,在模拟循环的每N次迭代时:

代码语言:javascript
复制
from cpython.exc cimport PyErr_CheckSignals

cdef Run(self):
    while True:
        # do some work
        PyErr_CheckSignals()

PyErr_CheckSignals将运行与signal模块一起安装的信号处理程序(这包括在必要时引发KeyboardInterrupt )。

PyErr_CheckSignals是相当快的,经常调用它是可以的。请注意,应该从主线程调用它,因为Python在主线程中运行信号处理程序。从工作线程调用它没有任何效果。

说明

由于信号是在不可预测的时间异步传递的,因此直接从信号处理程序运行任何有意义的代码都是有问题的。因此,Python对传入的信号进行排队。队列稍后将作为解释器循环的一部分进行处理。

如果您的代码是完全编译的,解释器循环永远不会执行,Python也没有机会检查和运行排队的信号处理程序。

票数 15
EN

Stack Overflow用户

发布于 2016-03-30 00:39:02

如果您试图在释放GIL的代码中处理KeyboardInterrupt (例如,因为它使用了cython.parallel.prange),则需要重新获取GIL才能调用PyErr_CheckSignals。下面的代码片段(改编自@nikita-nemkin上面的答案)说明了你需要做的事情:

代码语言:javascript
复制
from cpython.exc cimport PyErr_CheckSignals
from cython.parallel import prange

cdef Run(self) nogil:
    with nogil:
        for i in prange(1000000)
            # do some work but check for signals every once in a while
            if i % 10000 == 0:
                with gil:
                    PyErr_CheckSignals()
票数 3
EN

Stack Overflow用户

发布于 2013-05-27 19:27:57

当Cython运行与Python没有接口的部分时,释放GIL,在主线程中运行循环(休眠或检查模拟状态),并在except close中调用sim.Stop() (它可以设置一些模拟可以定期检查的标志)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16769870

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档