【问题标题】:Stopping embedded Python停止嵌入式 Python
【发布时间】:2010-11-28 02:28:09
【问题描述】:

我正在将 Python 解释器嵌入到 C 程序中。但是,通过PyRun_SimpleString() 运行某些 python 脚本时,可能会遇到无限循环或执行时间过长。考虑PyRun_SimpleString("while 1: pass"); 在防止主程序阻塞时,我认为我可以在线程中运行解释器。

如何停止在线程中运行的嵌入式解释器中执行 python 脚本而不杀死整个进程?

是否可以将异常传递给解释器?我应该将脚本包装在其他可以监听信号的脚本下吗?

PS:我可以在单独的进程中运行 python,但这不是我想要的 - 除非它是最后的手段......


更新:

所以,它现在可以工作了。再次感谢 Denis Otkidach!

如果我没看错,你必须做两件事:告诉解释器停止,return -1 在 PyRun_SimpleString() 运行的同一线程中。

要停止,有几种可能性:PyErr_SetString(PyExc_KeyboardInterrupt, "...")PyErr_SetInterrupt() - 第一种可能会让 Python 运行更多指令然后停止,后一种会立即停止执行。

对于return -1,您使用Py_AddPendingCall() 将函数调用注入到Python 执行中。文档从 2.7 和 3.1 版本开始提到它,但它也可以在早期的 Python 上运行(此处为 2.6)。从 2.7 和 3.1 开始,它也应该是线程安全的,这意味着您可以在不获取 GIL (?) 的情况下调用它。

所以可以重写下面的例子:

int quit() {
    PyErr_SetInterrupt();
    return -1;
}

【问题讨论】:

    标签: python process multithreading embedded-language python-c-api


    【解决方案1】:

    我希望能够中断任何正在运行的 Python 代码块,包括取消无限循环或只是一些长时间运行的代码。在我的应用程序中,提交并评估了单线程 Python 代码。中断请求可以随时到来。这个问题和答案对于帮助我真正实现这一目标至关重要。

    2019年看这个问题,这里的解决方案对我不起作用;我尝试以多种不同的方式使用Py_AddPendingCall(&quit, NULL);,但被调用的函数从未按预期执行,或者根本没有执行。当我提交 Py_FinalizeEx() 时,这导致 Python 引擎挂起并最终崩溃。我终于在这个非常有用的answer 中找到了我需要的类似问题。

    启动 Python 引擎后,我使用 Python 代码中的 threading 包检索线程 ID。我将其解析为一个 c long 值并保存。

    中断函数其实很简单:
    PyGILState_Ensure()
    PyThreadState_SetAsyncExc(threadId, PyExc_Exception)使用我之前保存的线程ID和一个通用异常类型
    PyGILState_Release()

    【讨论】:

    • 这似乎不是对这个问题的答案,而是一个后续问题,其中包含一个不必要的轶事中的后续问题的解决方案。 SO不是论坛。请仅使用答案来回答所提出的问题。如果您认为您的新问题和解决方案对其他人有用,您可以在引用此问题并描述新问题的地方发布一个新问题,然后将您的解决方案作为答案发布在那里。
    • 我在回答问题“如何停止在线程中运行的嵌入式解释器中执行 python 脚本而不杀死整个进程?”。最初接受的答案对我不起作用,但我想出了如何去做,所以我提供了另一种解决方案的信息。
    【解决方案2】:

    您可以使用Py_AddPendingCall() 添加一个引发异常的函数,以便在下一次检查间隔时调用(有关更多信息,请参阅sys.setcheckinterval() 上的文档)。这是一个带有Py_Exit() 调用的示例(这对我有用,但可能不是您需要的),将其替换为Py_Finalize()PyErr_Set*() 之一:

    int quit(void *) {
        Py_Exit(0);
    }
    
    
    PyGILState_STATE state = PyGILState_Ensure();
    Py_AddPendingCall(&quit, NULL);
    PyGILState_Release(state);
    

    这对于任何纯 python 代码来说都足够了。但请注意,一些 C 函数可以作为单个操作运行一段时间(有一个长时间运行正则表达式搜索的示例,但我不确定它是否仍然相关)。

    【讨论】:

    • 这看起来非常有趣,但它不适合最新的 Python 吗? (2.7 alpha 就在今天发布了。)但是,我可以升级到 Python 3.1 - 但那又如何呢?我应该通过Py_AddPendingCall()注册什么功能? PyErr_SetString()? Py_Exit()? Py_Finalize()?
    • Py_AddPendingCall 至少存在于 python 2.0(在 ceval.h 中定义)。我在答案中添加了示例代码。
    【解决方案3】:

    那么,python 解释器必须在嵌入程序之外的单独线程中运行,否则您将永远没有机会中断解释器。

    当你有这个时,也许你可以使用 Python API 异常调用之一来触发解释器中的异常?见Python C API Exceptions

    【讨论】:

      猜你喜欢
      • 2014-08-10
      • 1970-01-01
      • 2018-06-28
      • 2011-01-25
      • 2013-02-16
      • 1970-01-01
      • 1970-01-01
      • 2022-08-18
      • 1970-01-01
      相关资源
      最近更新 更多