停止嵌入式python

时间:2014-06-19 20:30:42

标签: python c++ embed

我在一个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的算法不是我的工作,我不应该改变它

4 个答案:

答案 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())