停止、暂停和恢复python解释器

经过前面的一系列铺垫,现在要迎来我们的终极成果了——在运行我们自定义的函数过程中,如果要停止、暂停和再恢复python解释器,应该如何操作呢?

如果自定义函数中有耗时操作应该如何处理呢?

如何通过python c api实现钩子的功能呢?

先上码:

 

int PythonRunner::tracer(PyObject *, _frame *, int, PyObject *)

{

    //Pause is requested...

    if (_instance->pauseRequested())

    {

        Py_BEGIN_ALLOW_THREADS;

        //If we are paused and no resume has been requested sleep

        while (!_instance->resumeRequested())

        {

            QThread::msleep(500);

        }

        Py_END_ALLOW_THREADS;

    }

    //Abort requested

    else if (true == _instance->interruptRequested())

    {

        Py_AddPendingCall(&PythonRunner::raiseException, NULL);

    }

 

    // Otherwise proceed normally.

    return 0;

}

 

int PythonRunner::raiseException(void *)

{

//    PyErr_SetInterrupt();

    PyErr_SetString(PyExc_KeyboardInterrupt, "Abort");

    return -1;

}

 

void PythonRunner::run()

{

    PyEval_SetTrace(PythonRunner::tracer, NULL);

 

    runPython();

}

   

 static int tracer(PyObject *, struct _frame *, int, PyObject *);

 static int raiseException(void *);

 

 

由于整个工程的代码贴上去会比较乱,只把主要的部分说下。

static int tracer(PyObject *, struct _frame *, int, PyObject *)该函数被用于注册回调, 用它可以实现钩子的功能。啥是钩子?简单来说就是执行每行代码前都会进入这个回调函数。注意struct _frame该结构体,需要包含#include 这个头文件,否则会报错。暂停、恢复和停止的功能也是在该函数中实现的。

 

我们知道在终端上运行python时,可以通过ctrl + c 来终止运行的python脚本,并且会弹出很多信息。我们的停止功能和这个相同,不过还有另一种接口调用。停止功能的函数需要返回-1,,并且调用PyErr_SetInterrupt()或PyErr_SetString(PyExc_KeyboardInterrupt, "Abort")。调用第一个是直接停止python解释器,不带有返回信息;调用第二个相当于使用ctrl + c来终止程序,带有返回信息,对用户输出内容这里包含About。异常停止的函数由c api Py_AddPendingCall()来调用。这里需要注意的是Py_AddPendingCall()该函数需要和python执行PyRun_SimpleString()的调用在同一个线程里面。

暂停的功能则是在调用每条指令前进行拦截。

 

 

为了防止自定义python中执行while 耗时操作,故将PyRun_SimpleString()放在线程中执行,这样就不会阻塞UI界面了。而我们也将回调函数注册到了线程里面。

这里面要注意的是当停止按钮按下后,被中断的线程需要根据对应的业务逻辑做对应的处理,有关线程的处理是很有考究的。

 

如果大家想要工程源码,可以在公众号后台留言。欢迎大家交流分享。

 

停止、暂停和恢复python解释器_第1张图片

 

 

停止、暂停和恢复python解释器_第2张图片

微信扫一扫
关注该公众号

你可能感兴趣的:(Python)