停止嵌入式Python
-
07-07-2019 - |
题
我正在将Python解释器嵌入到C程序中。但是,可能会发生这样的情况:通过运行某些python脚本时,PyRun_SimpleString()
将运行到无限循环或执行太长时间。考虑 PyRun_SimpleString(" while 1:pass");
在防止主程序阻塞时我想我可以在一个线程中运行解释器。
如何停止在线程中运行的嵌入式解释器中执行python脚本而不会终止整个过程?
是否可以将异常传递给解释器?我应该将脚本包装在一些可以收听信号的其他脚本下吗?
PS:我可以在一个单独的进程中运行python,但这不是我想要的 - 除非它是最后的手段......
<强>更新强>
所以,它现在有效。再次感谢Denis Otkidach!
如果我看到这一点,你必须做两件事:告诉解释器停止并在与PyRun_SimpleString()运行的同一个线程中 return -1
。
要停止,有一些可能性: PyErr_SetString(PyExc_KeyboardInterrupt,&quot; ...&quot;)
或 PyErr_SetInterrupt()
- 第一个可能让Python运行一些指令然后停止,后一个指令立即停止执行。
要 return -1
,您可以使用 Py_AddPendingCall()
将函数调用注入Python执行。文档从2.7和3.1版本开始就提到它,但它也运行在早期的Pythons上(这里是2.6)。从2.7和3.1它也应该是线程安全的,这意味着你可以在不获取GIL(?)的情况下调用它。
所以可以重写下面的例子:
int quit() {
PyErr_SetInterrupt();
return -1;
}
解决方案
您可以使用 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解释器必须在嵌入程序的单独线程中运行,否则你将永远不会有机会中断解释器。
如果你有这个,也许你可以使用Python API异常调用之一来在解释器中触发异常?请参阅 Python C API例外
我希望能够中断任何正在运行的Python代码块,包括取消无限循环或只是一些长时间运行的代码。在我的应用程序中,提交并评估单线程Python代码。中断请求可以随时发出。这个问题和答案对于帮助我实现这一目标至关重要。
在2019年看到这个问题,这里的解决方案对我不起作用;我尝试以很多不同的方式使用 Py_AddPendingCall(&amp; quit,NULL);
,但是被调用的函数从未按预期执行,或者根本没有执行。当我提交 Py_FinalizeEx()
时,这导致Python引擎挂起并最终崩溃。我终于找到了我在这个非常有用的回答类似问题时所需要的内容。
启动Python引擎后,我使用Python代码中的 threading
包检索线程id。我将其解析为c long值并保存。
中断功能实际上非常简单:
<代码> PyGILState_Ensure()代码>结果
PyThreadState_SetAsyncExc(threadId,PyExc_Exception)
使用我之前保存的线程ID和一般异常类型
<代码> PyGILState_Release()代码>结果