以前在开发python和c++混合语言的时候,总是采用简单的方法快速完成,shell的无比强大助力提供了无需代码的方案。但这样有几个问题一直无法很优雅的去作,一个是参数传递问题,由于shell不能传递太长的参数,所以只能用其它的方法来代替,比如临时文件或者系统通信方法,一点不直接。还有就是性能和系统设计方案的优雅的问题,性能不用说了,进程间的还是每次一起的,优雅木有。所以最近仔细研究了一下这方面的事情,为以后的开发作准备。以下对python和c++混合开发简称混合开发。
其实对于混合开发来说,最关键的部分是python提供的sdk,它提供了全部的混合开发的功能,有了它你就有了全部。但是,如果光拿sdk进行开发,那么基本上你会痛不欲生,python的sdk,那叫一个乱,当然,很多地方是出于性能上的考虑,但对于开发者来说,绝对是一个恶梦。但是我们有了boost.python,吼吼,终于说到正题了。boost.python帮我们解决了两个问题,首先一个,也是最重要的,解决了python sdk混乱的引用计数问题,提供了一致性的解决方案。其次,提供了基于C++模板技术的,统一的,高性能的封装。
先来看一个例子:考虑这样一个场景,对于使用python的web框架进行开发的人,django是一个简单实用的工具。如果我们用django进行前端开发,使用django的模板和orm工具,在后端我们可以使用c++来进行一些高性能的处理。比如进行一些大计算量的工作,然后把结果放入到数据库中供前端django使用。一种方法可能是完全采用python来开发,但是对于大计算量来说,python实在不是一个好主意。如果使用c++来开发,那么数据库怎么处理,我们可以借用django的orm,这样可以省去维护两个数据库操作的麻烦。
我们使用boost.python来处理python嵌入c++的问题,例子代码:
try{
object m=import("__main__");
object g=m.attr("__dict__");
exec_file(process.c_str(),g,g);
object eval=g["eval"];
object ret=eval(d);
}
catch(error_already_set const &){
LOG_NOTIFY<<"process python module call failed:";
PyErr_Print();
}
catch (...){
LOG_NOTIFY<<"process python module catch ...";
}
这样我们就简单的嵌入了python代码并取回了结果.
关于如何用boost.python进行混合开发的方法,网上有无数的教程,不再赘述了,说说在测试学习过程中遇到的问题。
1.首先的一个问题,就是关于多线程开发,boost.python是不支持多线程的,原因在于python sdk自身对多线程的处理也不好,在查找了相关的资料后发现,python在某一个版本以后,提供了一些多线程方面的支持,大致是这个样子:在初始化的时候加入
Py_Initialize();
PyEval_InitThreads();
PyEval_ReleaseThread(PyThreadState_Get());
结束的时候加入:
PyGILState_Ensure();
Py_Finalize();
先写一个简单的类:
class PyThreadStateLock
{
public:
PyThreadStateLock(void)
{
state = PyGILState_Ensure( );
}
~PyThreadStateLock(void)
{
PyGILState_Release( state );
}
private:
PyGILState_STATE state;
};
在线程中所有使用python的地方之前加入:
?1 |
PyThreadStateLock lock;
|
实测证明,这个东西的效果比自己写的效果要好,因为它可以在python内部进行一定的线程轮换机制,就是说如果你有多个c++线程都运行到python嵌入部分,那么在python内部可以有一些线程间的调度。这个是我目测日志发现的,并没有经过代码的洗刷,只是主观意测。
2.关于boost.python,在boost.python2.0版本,也就是目前最新的boost1.46.1提供的版本,没有提供对Py_Finalize()的支持,也就是说,在你整个进程的内部,实际上只共享了一个python解释器,这样你就没有办法通过Py_Finalize()来释放python所占用的内存,而对于python解释器的内部的内存管理机制而言,一但python解释器分配了内存,就会被cache起来而不会立刻释放。这个意思就是说在一些大型的项目中我们需要关注python解释的内存使用问题。实际测试过程中发现,python解释器也会释放一些不用的内存,但这个过程很慢。如果你需要内存理论上可以用gc.collect来手工释放,但实测效果不明显.这个问题目前没有好的解决方法.
3.对于boost.python没有支持的功能,可以使用python原生的sdk来解决,同时我们也需要对python sdk的相关系统有所了解,了解其真实的运行方式,这样才能真正知道我们作了什么,没作什么.感谢一下开源项目,源码之前,了无秘密.
4.关于django的,django出于效率的考虑,cache了大部分可以cache的东西,但这对于只是想嵌入使用一下orm的混合开发人员来说,其实没太大意义,反而如果数据库内容量比较大的时候,会导致python解释器占用大量的内存而得不到释放.这个的解决方法是在每次使用django orm 使用过后,对其cache进行清空处理,代码:
from django.db.models.loading import AppCache
cache = AppCache()
from django.utils.datastructures import SortedDict
cache.app_store = SortedDict()
cache.app_models = SortedDict()
cache.app_errors = {}
cache.handled = {}
cache.loaded = False
当然如果你确实需要orm的cache,比如说经常性的导出数据,那么可以不清.
5.其实boost.python也可以进行c++代码的python嵌入,可能这种模式用的更多一些,只是这里没有用到.
总的来说,我们得到了一种进行混合开发的方法,我们可以嵌来嵌去的,嵌来嵌去的,来嵌去的,嵌去的,去的,的...
更多推荐
最近进行python和c++混合语言开发的一点体会
发布评论