龙空技术网

C++ 多线程调用Python脚本

爱音乐的程序员小新人 308

前言:

现时你们对“python如何调用其他py里的函数”大概比较关心,各位老铁们都想要分析一些“python如何调用其他py里的函数”的相关内容。那么小编在网上网罗了一些有关“python如何调用其他py里的函数””的相关知识,希望姐妹们能喜欢,咱们一起来了解一下吧!

由于Python解释器有全局解释所GIL的原因,导致在同一时刻只能有一个线程拥有解释器,所以在C++多线程调用python脚本时,需要控制GIL,线程获取GIL。

在主线程中初始化Python解释器环境,代码如下:

{ Py_Initialize(); //初始化Python环境 if ( !Py_IsInitialized() ) //检测是否初始化成功 { return NULL; } else { PyEval_InitThreads(); //开启多线程支持 int nInit = PyEval_ThreadsInitialized(); //检测线程支持是否开启成功 if ( nInit ) { PyEval_SaveThread(); //因为调用PyEval_InitThreads成功后,当前线程就拥有了GIL,释放当前线程的GIL, } } }然后可以创建子线程,在子线程调用中 加入如下代码:int nHold = PyGILState_Check() ; //检测当前线程是否拥有GIL PyGILState_STATE gstate; if ( !nHold ) { gstate = PyGILState_Ensure(); //如果没有GIL,则申请获取GIL } Py_BEGIN_ALLOW_THREADS; Py_BLOCK_THREADS;/**************************以下加入需要调用的python脚本代码 Begin***********************//**************************以下加入需要调用的python脚本代码 End***********************/ Py_UNBLOCK_THREADS; Py_END_ALLOW_THREADS; if (!nHold) { PyGILState_Release(gstate); //释放当前线程的GIL }

boost::python对Python原生的C API有较好的封装,可以很方便通过C++对python脚本进行调用一下是一些学习总结,以便今后需要使用的时候能快速使用

假设有python模块 School.py 包含类 Student 和 函数 Call 和返回类对象的CallClass方法

class Student(): def __init__(name,age,properties): self.name = name self.age = age self.properties = proterties def show(): print(self.name, slef.age, self.properties) def Call(p1,p2): print(p1,p2) return "yes" def CallClass(): s = Student("universal",20,"good") return s

以下为C++调用python脚本代码:

1> 在C++中构造python中定义的类,并且调用类方法

boost::python::handle<>* school_module = NULL;string strModule = "School";school_module = new boost::python::handle<>(PyImport_ImportModule((char*)strModule.c_str())); //通过模块名称获取模块handleboost::python::object main_module(*manager_module); //转化为boost::python::object类型表示的模块 boost::python::object main_namespace = main_module.attr("__dict__"); //得到模块内的字典,字典中包含了 所有的类和函数boost::python::handle<> Student; //定义一个Student类 的handle//得到Student类的实例,参数可以任意传递 比如以下设置properties为一个dictStudent = boost::python::handle<>((PyRun_String("Student('alen',30,{\"errorcode\":0, \"message\":\"execute succeed\"})", Py_eval_input,main_namespace.ptr(), main_namespace.ptr()))); /*********以下将properties设置为一个tupleStudent = boost::python::handle<>((PyRun_String("Student('alen',30,(1,2,3,4,5))", Py_eval_input,main_namespace.ptr(), main_namespace.ptr())));**********/ /*********以下将properties设置为一个listStudent = boost::python::handle<>((PyRun_String("Student('alen',30,[1,2,3,4,5])", Py_eval_input,main_namespace.ptr(), main_namespace.ptr())));**********//**********//通过Student类调用类方法showboost::python::object result = boost::python::call_method<boost::python::object>(Student.get(), "show");

2>调用脚本中的函数 Call 假设传递的第一个参数为string 第二个为int

boost::python::handle<>* school_module = NULL;string strModule = "School";school_module = new boost::python::handle<>(PyImport_ImportModule((char*)strModule.c_str())); //通过模块名称获取模块handleboost::python::object result = boost::python::call_method<boost::python::object>(school_module->get(),"Call","schoolname",2);

3>调用脚本时,可以传递各种参数,boost 已经封装了boost::python::dict 对应dict boost::python::tuple对应 tuple

比如构造dict参数,代码如下:

boost::python::dict inParams;inParams.setdefault<std::string,std::string>("name","clear");inParams.setdefault<std::string,std::string>("code","56821334");inParams.setdefault<std::string,int>("number",123456);

4>处理返回的数据比如 python类类型

boost::python::handle<>* school_module = NULL;string strModule = "School";school_module = new boost::python::handle<>(PyImport_ImportModule((char*)strModule.c_str())); //通过模块名称获取模块handleboost::python::object student = boost::python::call_method<boost::python::object>(school_module->get(),"CallClass");//可以通过返回的类对象 继续调用类Student 的 show方法 如下:boost::python::object q = boost::python::call_method<boost::python::object>(student.ptr(), "show");//也可以获取类的属性值 比如 name string 类型 和 age Int类型boost::python::object obj_dict = student.attr("__dict__"); //获取对象的字典//获取nameboost::python::object name = obj_dict["name"];std::string sname = boost::python::extract<std::string>(name);//获取ageboost::python::object age = obj_dict["age"];int age = boost::python::extract<int>(age);将全局解释器锁和线程的相关操作用类封装,使用构造函数和析构函数 去做locker 和 unlocker的操作/*全局解释和线程锁*/class PyGILThreadLock{public: PyGILThreadLock() { _save = NULL; nStatus = 0; nStatus = PyGILState_Check() ; //检测当前线程是否拥有GIL PyGILState_STATE gstate; if ( !nStatus ) { gstate = PyGILState_Ensure(); //如果没有GIL,则申请获取GIL nStatus = 1; } _save = PyEval_SaveThread(); PyEval_RestoreThread(_save); } ~PyGILThreadLock() { _save = PyEval_SaveThread(); PyEval_RestoreThread(_save); if (nStatus) { PyGILState_Release(gstate); //释放当前线程的GIL } } private: PyGILState_STATE gstate; PyThreadState *_save; int nStatus;};在代码中调用时,只需要{ PyGILThreadLock locker;///////以下添加python调用代码}

使用boost::python的时候捕获异常获取异常信息

std::string GetPythonErrorInfo(void) { using namespace boost::python; PyObject *exc,*val,*tb; PyErr_Fetch(&exc,&val,&tb); PyErr_NormalizeException(&exc,&val,&tb); handle<> hexc(exc),hval(allow_null(val)),htb(allow_null(tb)); if(!hval) { return extract<std::string>(str(hexc)); } else { object traceback(import("traceback")); object format_exception(traceback.attr("format_exception")); object formatted_list(format_exception(hexc,hval,htb)); object formatted(str("").join(formatted_list)); return extract<std::string>(formatted); } } 以下为VC控制台测试程序#include "stdafx.h"#include <Windows.h>#include <iostream>#include <process.h>#include <boost/python.hpp>using namespace std; #define Check_Init(init) \ if(!init){\ cout<<"请先通过init指令初始化python环境"<<endl;\ goto __next;\ } bool bInit = false;std::string strModule = "manager"; unsigned int __stdcall ThreadCall(void* lparam){ char szMessage[1024] = { 0 }; int id = GetCurrentThreadId(); sprintf_s(szMessage,sizeof(szMessage),"thread id: %d ",id); std::string sResult = ""; boost::python::handle<>* manager_module = NULL; for ( int i = 0 ; i < 2000 ; i ++) { PyGILThreadLock locker; manager_module = new boost::python::handle<>(PyImport_ImportModule((char*)strModule.c_str())); sResult = boost::python::call_method<std::string>(manager_module->get(),"threadcall",szMessage); cout<<sResult.c_str()<<endl; delete manager_module; manager_module = NULL; } return 0;} void callsay(const char* szMessage){ boost::python::handle<>* manager_module = NULL; std::string sResult = ""; PyGILThreadLock locker; try { manager_module = new boost::python::handle<>(PyImport_ImportModule((char*)strModule.c_str())); sResult = boost::python::call_method<std::string>(manager_module->get(),"say",szMessage); } catch(...) { delete manager_module; manager_module = NULL; cout<<"捕获一个异常在callsay方法中"<<endl; } delete manager_module; manager_module = NULL;} int _tmain(int argc, _TCHAR* argv[]){ char szCommand[20]={0} ; cout<<"请输入指令"<<endl; cin>>szCommand; while ( strcmp("quit",szCommand) != 0 ) { if ( strcmp("threadcall",szCommand) == 0 ) { Check_Init(bInit); for ( int i = 0 ; i < 5; i++ ) { _beginthreadex(NULL, 0, ThreadCall, NULL, 0, NULL); } } else if ( strcmp("init",szCommand) == 0 ) { if ( bInit ) { cout<<"Python 环境已经初始化"<<endl; continue; } Py_Initialize(); //初始化Python环境 if ( !Py_IsInitialized() ) //检测是否初始化成功 { cout<<"Python环境初始化失败"<<endl; return NULL; } else { PyEval_InitThreads(); //开启多线程支持 int nInit = PyEval_ThreadsInitialized(); //检测线程支持是否开启成功 if ( nInit ) { PyEval_SaveThread(); //因为调用PyEval_InitThreads成功后,当前线程就拥有了GIL,释放当前线程的GIL, } bInit = true; cout<<"Python环境初始化成功,退出前请使用free指令释放Python环境"<<endl; } } else if ( strcmp("say",szCommand) == 0 ) { Check_Init(bInit); std::string msg = "Python Manager"; callsay(msg.c_str()); } else if ( strcmp("free",szCommand) == 0 ) { Py_Finalize(); bInit = false; cout<<"Python解释器环境被释放"<<endl; } else{ cout<<"未识别的指令信息"<<endl; }__next: memset(szCommand,0,20); cin>>szCommand; } system("pause"); return 0;}

添加一个测试过程中的代码, 因为还封装了类所以单独编译不过,用来标记一下吧 ,方便下次在使用的时候可以快速的重新学习

// PythonManager.cpp : Defines the entry point for the console application.// #include "stdafx.h"#include <Windows.h>#include <iostream>#include <process.h>// #include <boost/python.hpp>// #include "Python.h"#include "PythonAssister.h"using namespace std; #define Check_Init(init) \ if(!init){\ cout<<"请先通过init指令初始化python环境"<<endl;\ goto __next;\ } bool bInit = false;std::string strModule = "manager"; unsigned int __stdcall ThreadCall(void* lparam){ char szMessage[1024] = { 0 }; int id = GetCurrentThreadId(); sprintf_s(szMessage,sizeof(szMessage),"thread id: %d ",id); std::string sResult = ""; boost::python::handle<>* manager_module = NULL; for ( int i = 0 ; i < 2000 ; i ++) { PyGILThreadLock locker;// int nHold = PyGILState_Check() ; //检测当前线程是否拥有GIL // PyGILState_STATE gstate; // if ( !nHold ) // { // gstate = PyGILState_Ensure(); //如果没有GIL,则申请获取GIL // } // Py_BEGIN_ALLOW_THREADS; // Py_BLOCK_THREADS; manager_module = new boost::python::handle<>(PyImport_ImportModule((char*)strModule.c_str())); sResult = boost::python::call_method<std::string>(manager_module->get(),"threadcall",szMessage); cout<<sResult.c_str()<<endl;// Py_UNBLOCK_THREADS; // Py_END_ALLOW_THREADS; // if (!nHold) // { // PyGILState_Release(gstate); //释放当前线程的GIL // } } return 0;} void calltest(){ PyGILThreadLock locker; boost::python::handle<>* manager_module = NULL; manager_module = new boost::python::handle<>(PyImport_ImportModule((char*)strModule.c_str())); boost::python::object result = boost::python::call_method<boost::python::object>(manager_module->get(),"calltest"); cout<< result.ptr()->ob_type->tp_name<<endl; boost::python::object q = boost::python::call_method<boost::python::object>(result.ptr(), "show"); boost::python::object r1 = result.attr("__dict__"); boost::python::object r2 = r1["name"];// boost::python::call_method<boost::python::object>(r1,"__getdict__","name"); std::string sname = boost::python::extract<std::string>(r2); cout<<sname.c_str()<<endl; delete manager_module; manager_module = NULL; } void classtest(){ PyGILThreadLock locker; boost::python::handle<>* manager_module = NULL; try { manager_module = new boost::python::handle<>(PyImport_ImportModule((char*)strModule.c_str())); boost::python::object main_module(*manager_module); boost::python::object main_namespace = main_module.attr("__dict__"); boost::python::handle<> Student; Student = boost::python::handle<>((PyRun_String( "Student('alen',30,{\"errorcode\":0, \"message\":\"execute succeed\"})", Py_eval_input, main_namespace.ptr(), main_namespace.ptr()))); boost::python::object result = boost::python::call_method<boost::python::object>(Student.get(), "show"); } catch(...) { PyErr_Print(); PyErr_Clear(); } } void calldict() { boost::python::handle<>* manager_module = NULL; boost::python::dict mydict; int nHold = PyGILState_Check() ; //检测当前线程是否拥有GIL PyGILState_STATE gstate; if ( !nHold ) { gstate = PyGILState_Ensure(); //如果没有GIL,则申请获取GIL } Py_BEGIN_ALLOW_THREADS; Py_BLOCK_THREADS; try { boost::python::dict inParams; inParams.setdefault<std::string,std::string>("name","clear"); inParams.setdefault<std::string,std::string>("code","56821334"); inParams.setdefault<std::string,int>("number",123456); int nLenDict = len(inParams); const char* szType = inParams.ptr()->ob_type->tp_name; boost::python::list dictlist; dictlist = inParams.items(); int nLenList = len(dictlist); for ( int i = 0 ; i< nLenList; i++ ) { boost::python::object obj; obj = dictlist.pop(); const char* szType = obj.ptr()->ob_type->tp_name; int n = PyType_Check(obj.ptr()); int nLenTuple = len(obj); for ( int j = 0 ; j <nLenTuple; j++ ) { int n1 = PyType_Check(((boost::python::object)obj[j]).ptr()); std::string value = boost::python::extract<std::string>(obj[j]); boost::python::extract<const std::string&>ex((obj[j])); if ( ex.check() ) { cout<<"yes it is string"<<endl; } cout<<value.c_str()<<endl; } } //boost::python::tuple boost::python::object itemTuple; itemTuple = dictlist.pop(); while ( itemTuple != NULL ) { int nLen = len(itemTuple); string strKey = boost::python::extract<std::string>(itemTuple[0]); string strValue = boost::python::extract<std::string>(itemTuple[1]); itemTuple = dictlist.pop(); int a = 10; } manager_module = new boost::python::handle<>(PyImport_ImportModule((char*)strModule.c_str())); //mydict = boost::python::call_method<boost::python::dict>(manager_module->get(),"calldict",inParams); boost::python::object result = boost::python::call_method<boost::python::object>(manager_module->get(),"calldict",inParams); const char* szType1 = result.ptr()->ob_type->tp_name; cout<<"Type : "<<szType1<<endl; } catch(...) { // delete manager_module; // manager_module = NULL; cout<<"捕获一个异常在calldict方法中"<<endl; } if ( NULL != manager_module ) { delete manager_module; manager_module = NULL; } Py_UNBLOCK_THREADS; Py_END_ALLOW_THREADS; if (!nHold) { PyGILState_Release(gstate); //释放当前线程的GIL } } void callsay(const char* szMessage){ boost::python::handle<>* manager_module = NULL; std::string sResult = ""; int nHold = PyGILState_Check() ; //检测当前线程是否拥有GIL PyGILState_STATE gstate; if ( !nHold ) { gstate = PyGILState_Ensure(); //如果没有GIL,则申请获取GIL } Py_BEGIN_ALLOW_THREADS; Py_BLOCK_THREADS; try { manager_module = new boost::python::handle<>(PyImport_ImportModule((char*)strModule.c_str())); sResult = boost::python::call_method<std::string>(manager_module->get(),"say",szMessage); } catch(...) { delete manager_module; manager_module = NULL; cout<<"捕获一个异常在callsay方法中"<<endl; } delete manager_module; manager_module = NULL; Py_UNBLOCK_THREADS; Py_END_ALLOW_THREADS; if (!nHold) { PyGILState_Release(gstate); //释放当前线程的GIL } } int _tmain(int argc, _TCHAR* argv[]){ char szCommand[20]={0} ; cout<<"请输入指令"<<endl; cin>>szCommand; while ( strcmp("quit",szCommand) != 0 ) { if ( strcmp("threadcall",szCommand) == 0 ) { Check_Init(bInit); for ( int i = 0 ; i < 5; i++ ) { _beginthreadex(NULL, 0, ThreadCall, NULL, 0, NULL); } } else if ( strcmp("classtest",szCommand) == 0 ) { classtest(); } else if ( strcmp("init",szCommand) == 0 ) { if ( bInit ) { cout<<"Python 环境已经初始化"<<endl; continue; } Py_Initialize(); //初始化Python环境 if ( !Py_IsInitialized() ) //检测是否初始化成功 { cout<<"Python环境初始化失败"<<endl; return NULL; } else { PyEval_InitThreads(); //开启多线程支持 int nInit = PyEval_ThreadsInitialized(); //检测线程支持是否开启成功 if ( nInit ) { PyEval_SaveThread(); //因为调用PyEval_InitThreads成功后,当前线程就拥有了GIL,释放当前线程的GIL, } bInit = true; cout<<"Python环境初始化成功,退出前请使用free指令释放Python环境"<<endl; } } else if ( strcmp("say",szCommand) == 0 ) { Check_Init(bInit); std::string msg = "Python Manager"; callsay(msg.c_str()); } else if ( strcmp("calldict",szCommand) == 0 ) { Check_Init(bInit); std::string msg = "Python Manager"; calldict(); } else if ( strcmp("free",szCommand) == 0 ) { int nHold = PyGILState_Check() ; //检测当前线程是否拥有GIL PyGILState_STATE gstate; if ( !nHold ) { gstate = PyGILState_Ensure(); //如果没有GIL,则申请获取GIL } Py_Finalize(); bInit = false; cout<<"Python解释器环境被释放"<<endl; } else{ cout<<"未识别的指令信息"<<endl; }__next: memset(szCommand,0,20); cin>>szCommand; } system("pause"); return 0;}

标签: #python如何调用其他py里的函数 #python调用其他py #python调用c语言脚本 #多个线程调用一个函数的方法 #c语言如何调用python