我在一个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的算法不是我的工作,我不应该改变它
答案 0 :(得分:5)
这是基于粗略的python知识,并快速阅读python文档。
PyThreadState_SetAsyncExc
允许您将一个异常注入正在运行的python线程。
在某个线程中运行python解释器。在另一个线程中,PyGILState_STATE
然后PyThreadState_SetAsyncExc
进入主线程。 (这可能需要一些前期工作来教授python解释器关于第二个线程)。
除非你运行的python代码充满了“catch alls”,否则这会导致它终止执行。
您还可以查看代码以创建python子解释器,这将允许您在旧脚本关闭时启动新脚本。
Py_AddPendingCall
也很有诱惑力,但周围有足够的警告可能没有。
答案 1 :(得分:4)
很抱歉,但您的选择很短。你可以改变python代码(ok,插件 - 不是一个选项)或者在另一个PROCESS上运行它(之间有一些不错的ipc)。然后你可以使用系统api擦除它。
答案 2 :(得分:2)
所以,我终于想到了一个解决方案(更多的解决方法)。
不是终止运行算法的线程 - 让我们称之为T1 - 我创建了另一个-T2 - 与当时相关的数据集。
在每个帖子中我都这样做:
thread_counter+=1; //global variable
int thisthread=thread_counter;
在给出python的解决方案后,我只是验证哪个是最“最近的”,来自T1或T2的那个:
if(thisthread==thread_counter){
/*save the solution and treat it */
}
计算机工作的条件显然不是最佳解决方案,但它符合我的目的。
感谢帮助人员
答案 3 :(得分:2)
我一直在考虑这个问题,并且我同意副译员可能会为您提供一个可能的解决方案https://docs.python.org/2/c-api/init.html#sub-interpreter-support。它支持创建新解释器和结束现有解释器的调用。臭虫和警告部分描述了一些问题,这些问题取决于您的架构可能会或可能不会出现问题。
另一种可能的解决方案是使用python multiprocessing模块,并在工作线程中测试一个全局变量(类似 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())