停止嵌入python

Stop embedded python

本文关键字:python      更新时间:2023-10-16

我在c++插件中嵌入python。该插件在每次会话期间调用python算法数十次,每次向算法发送不同的数据。一切顺利

但是现在我有一个问题:算法有时需要几分钟来求解并返回一个解,而在这段时间内,条件的变化往往会使解变得无关紧要。因此,我想要的是在任何时刻停止算法的运行,并在其他数据集之后立即运行它。

这是我目前为止嵌入python的c++代码:

void py_embed (void*data){

counter_thread=false;
PyObject *pName, *pModule, *pDict, *pFunc;
//To inform the interpreter about paths to Python run-time libraries
Py_SetProgramName(arg->argv[0]);
if(!gil_init){
    gil_init=1;
    PyEval_InitThreads();
    PyEval_SaveThread();
}
PyGILState_STATE gstate = PyGILState_Ensure();
// Build the name object
pName = PyString_FromString(arg->argv[1]);
if( !pName ){
    textfile3<<"Can't build the object "<<endl;
}
// Load the module object
pModule = PyImport_Import(pName);
if( !pModule ){
    textfile3<<"Can't import the module "<<endl;
}
// pDict is a borrowed reference 
pDict = PyModule_GetDict(pModule);
if( !pDict ){
    textfile3<<"Can't get the dict"<<endl;
}
// pFunc is also a borrowed reference 
pFunc = PyDict_GetItemString(pDict, arg->argv[2]);
if( !pFunc || !PyCallable_Check(pFunc) ){
    textfile3<<"Can't get the function"<<endl;
}
/*Call the algorithm and treat the data that is returned from it
 ...
 ...
 */
// Clean up
Py_XDECREF(pArgs2);
Py_XDECREF(pValue2);
Py_DECREF(pModule);
Py_DECREF(pName);
PyGILState_Release(gstate);
counter_thread=true;
_endthread(); 

};

编辑:python的算法不是我的工作,我不应该改变它

这是基于对python的粗略了解,以及快速阅读python文档。

PyThreadState_SetAsyncExc允许你在运行的python线程中注入异常。

在某个线程中运行python解释器。在另一个线程中,PyGILState_STATE然后PyThreadState_SetAsyncExc进入主线程。(这可能需要一些前期工作来教python解释器关于第二个线程的内容)。

除非你正在运行的python代码充满了"catch all ",否则这会导致它终止执行。

您还可以查看代码以创建python子解释器,这将允许您在旧脚本关闭时启动新脚本。

Py_AddPendingCall也是诱人的使用,但周围有足够的警告,也许不是。

对不起,你的选择很短。您可以更改python代码(好吧,插件-不是一个选项)或在另一个PROCESS上运行它(中间有一些不错的ipc)。然后你可以使用系统api来清除它

所以,我终于想到了一个解决方案(更像是一个变通的方法)。

我没有终止正在运行算法的线程(我们称它为T1),而是创建了另一个线程(t2),其中包含当时相关的数据集。

在每个线程中我都这样做:

thread_counter+=1; //global variable
int thisthread=thread_counter;

,在python给出解决方案后,我只需验证哪个是最新的,来自T1还是来自T2:

if(thisthread==thread_counter){
     /*save the solution and treat it */
}

就计算机的工作量而言,这显然不是最好的解决方案,但它满足了我的目的。

谢谢大家的帮助

我一直在思考这个问题,我同意子解释器可能为您提供一个可能的解决方案https://docs.python.org/2/c-api/init.html#sub-interpreter-support。它支持创建新的解释器和结束现有解释器的呼吁。虫子&注意事项部分描述了一些问题,这些问题取决于您的体系结构,可能会出现问题,也可能不会出现问题。

另一个可能的解决方案是使用python多处理模块,并在工作线程中测试一个全局变量(类似于time_to_die)。然后从父进程中获取GIL,设置变量,释放GIL并等待子进程完成。

但是我想到了另一个主意。为什么不直接使用fork(),在子线程中初始化你的python解释器,当父线程决定该结束python线程时,就杀死它。像这样:

void process() {
    int pid = fork();
    if (pid) {
        // in parent
        sleep(60);
        kill(pid, 9);   
        }
    else{
        // in child
        Py_Initialize();
        PyRun_SimpleString("# insert long running python calculation");
        }
    }

(这个例子假设*nix,如果你在windows上,替换CreateProcess()/TerminateProcess())