限制嵌入的执行时间Python

Limiting execution time of embedded Python

如果我在 C 或 C++ 程序中嵌入 Python 解释器,如 this example,是否有任何方法可以限制解释器运行的时间?有什么可以阻止 Python 代码进入无限循环,从而阻止 PyObject_CallObject(或等价物)返回吗?

同样,如果Python代码创建了一个新线程,有没有什么可以阻止这个线程进入无限循环并永远运行?

如您在 the docs 中所见,PyObject_CallObject 没有机制来限制函数 运行 的长度。据我所知,也没有 Python C API 函数允许您暂停或终止解释器使用的线程。

因此,我们必须在停止线程的方式上更具创造性 运行ning。我可以想到 3 种方法(从 safest/cleanest 到最危险的...

轮询您的主要应用程序

这里的想法是,您的 Python 函数可以 运行 很长时间,只需调用主应用程序中的另一个函数,使用 C API 看看它是否应该关掉。一个简单的 True/False 结果将允许您优雅地终止。

这是最安全的解决方案,但需要您更改 Python 代码。

使用例外

由于您嵌入了解释器,因此您已经在使用 C API,因此可以使用 PyThreadState_SetAsyncExc to force an exception to be raised in the offending thread. You can find an example that uses this API here。虽然它是 Python 代码,但相同的功能将在您的主应用程序中运行。

此解决方案不太安全,因为它要求代码不捕获异常并在之后保持可用状态。

使用OS终止线程

我不打算讨论这个,因为它本质上是不安全的。有关原因的一些解释,请参阅 Is there any way to kill a Thread in Python?

如果您需要在某些实时系统中控制延迟和抖动,请嵌入 "StacklessPython" - Python 和支持的协程。用于 "Twisted Web Server".

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

我使用上面@Peter Brittain 2016 年 7 月的回答中的中间方法。

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

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

非常感谢最初的问题和 Peter Brittain!