2

c++ 通过c api调用python跑cnn前向运算的一些问题

 2 years ago
source link: https://www.zoucz.com/blog/2020/11/03/c1e17640-1da5-11eb-90b5-eb40e9720ed0/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

c++ 通过c api调用python跑cnn前向运算的一些问题

作者: 邹成卓 2020-11-03 15:25:32 分类: c++,机器学习

标签: c++, python

评论数:

有比较成熟的c++ rpc框架,想要基于python代码快速搭建一个线上可用的rpc服务时,可用用c api的方式调用python脚本,将其封装成一个rpc服务。
这种方式的优点是相比将python代码翻译成tensorflow/pytorc的c++ 模块调用,开发成本要小很多;缺点是性能较低,只能做到单个并发,只适合于有成熟c++ rpc框架且无python版rpc框架的情况。
开发过程中有一些要注意的问题,在此记录一下。 我要说话

embedding-python文档 我要说话

初始化,python解释器在同一个线程中可以初始化多次,能正常返回,但是在不同线程初始化的适合,整个程序会直接core掉。另外初始化的时候有一套解释器拉起/so库选择的规则,在文档中有描述,使用的时候要格外注意。 我要说话

python c api线程安全文档 我要说话

多线程调用c api封装的函数时,需要加全局锁,否则可能会导致程序挂掉。我要说话

c api args文档 我要说话

标注库string的传递,Py_BuildValue会根据\0自动判断c str的结尾,并传递给python 我要说话

PyObject *pInitArgs = Py_BuildValue("(s)", _sModelPath.c_str());

二进制数据块的传递,此时注意标识不再是s了,而是s#,这样Py_BuildValue就不会再根据\0判断数据结束,而是根据后面传入的数据长度来判断。 我要说话

PyObject *pArgs = Py_BuildValue("(s#)", c, audioBuf.size());

传递二进制数据加上别的格式的数据,将别的数据依次往后加就行了 我要说话

PyObject *pArgs = Py_BuildValue("(s#,i)", c, audioBuf.size(), iAudioFormat);

python c api数据结构描述文档 我要说话

可参考此文档解析从python返回的数据结构,如解析元组类型: 我要说话

if(pRet && PyTuple_Check(pRet) && PyTuple_Size(pRet) == 2){
    PyObject* a = PyTuple_GetItem(pRet, 0);
    PyObject* b = PyTuple_GetItem(pRet, 1);
    PyArg_Parse( a, "i", &c );
    PyArg_Parse( b, "i", &d);
} else {
    c = -1;
    d = -1;
}

python c api引用计数文档 我要说话

Py_Object是所有py c类型的基类,它保存了一个指向python对象的指针和对象的引用计数,在使用完后要调用一下Py_DECREF/Py_XDECREF来减一个引用计数,引用计数到0时会调用python对象的析构函数。其中Py_DECREF需要明确指针非null,而Py_XDECREF则无所谓。 我要说话

cnn前向运算不能跨线程

这里遇到了一个奇怪的问题,python中cnn的前向运算无法跨线程,最开始试了TensorFlow,后来换成PyTorch也是一样。 我要说话

具体表现是,在a线程中初始化python解释器,然后: 我要说话

  • 在a线程或者b线程中初始化tf/pytorch,加载模型,可以成功
  • 在a线程调用前向运算的函数,可以成功
  • 在b线程调用前向运算的函数,会一直卡在函数调用的位置,不抛异常,也不返回
  • 在a/b线程中调用除了前向运算之外的其它函数,都可以成功

原因暂时没有去探究,先记录一下现象。所以这种做法只适合用来快速搭建demo。真正实现高性能服务的话还是要使用c++版本的tensorflow或者pytorch,来多线程调用,或者是run batch并行计算。我要说话

本文链接:https://www.zoucz.com/blog/2020/11/03/c1e17640-1da5-11eb-90b5-eb40e9720ed0/我要说话

☞ 参与评论我要说话


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK