最近进行python和c++混合语言开发的一点体会

37 篇文章 0 订阅

以前在开发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嵌入,可能这种模式用的更多一些,只是这里没有用到.

总的来说,我们得到了一种进行混合开发的方法,我们可以嵌来嵌去的,嵌来嵌去的,来嵌去的,嵌去的,去的,的...

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值