c++调用python脚本,指针快速传递
Posted 柯西的笔
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++调用python脚本,指针快速传递相关的知识,希望对你有一定的参考价值。
优秀的判断力来自经验,但经验来自错误的判断。–Fred Brooks
1、python以开发速度快著称。
2、python在数据处理方面具备强大的优势。
尤其在深度学习与机器学习方面,虽然现在有pytorch、tensorflow在部署上提供了像libtorch的c++版本,但那也只包括模型推理部分。如果在前期预处理上也用c++实现,那会是一件十分麻烦的事情。
因此,想通过c++调用python中函数的方式,将数据实现互传。(踩了许多的坑,网上有许多通过list或者tuple来传递的,如果是小数据也没什么问题。但如果遇到医疗这样的大数据,会需要极大的内存开销。本文将采用numpy指针的方式来传递数据,在内存开销与速度上都有极大的提升)。
此处环境配置是为了在无安装python环境的机子上运行。(如果电脑已安装环境就不需要拷贝,只需将环境变量加入即可)。
注意:python与c++的位数一定要对应,例如全为32位或者全为64位。
新建一个项目,将python安装的include与libs,拷贝到c++运行目录下。
由于python安装是没有debug模式的,但又需要在c++中使用到debug模式。
方法一:直接将libs文件夹的python38.lib复制一份该名称为python38_d.lib。(该方式不推荐,后续代码释放内存会有问题)
方法二:修改include下的pyconfig.h。
将pragma comment(lib,"python38_d.lib")改为pragma comment(lib,"python38.lib"),并且注释掉 # define Py_DEBUG
添加python库
将python安装目录下的DLLs与Lib拷贝c++到运行目录下(此处默认你安装了Numpy)。
拷贝python38.dll到c++运行目录(python安装目录下的文件)。
上述准备材料即准备完成。
打开vs属性管理器添加:
1.包含库目录添加之前拷贝来的include以及Lib下的numpy。
2.库目录添加libs以及Lib下的numpy的lib。
3.连接器输入添加python38.lib和npymath.lib。
以上的配置都包含了numpy,如果不想用numpy,也可以不添加numpy的任何操作。数据传输也是可以用list或者tuple来完成。但经我实验发现,numpy的数据传输方式内存开销起码节约5倍以上,速度也快5倍以上。
using namespace std;
int main()
{
//指定python.exe位置 python的环境。后来在迁移环境时,将include libs放在工程目录下,指定工程目录就可以
Py_SetPythonHome(L"./");//指定python.exe位置需要修改成自己的 python的环境
//初始化Python环境
Py_Initialize();
//初始化Numpy
import_array();
// 将当前目录加入sys.path 这两行的意思是你的主目录位置:是在工程目录下因此要把.py文件放到该目录下!。也可以自己定义
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
PyRun_SimpleString("import os");
PyRun_SimpleString("print(os.listdir())");
//导入模块
PyObject* pModule = PyImport_ImportModule("candpython");
//导入函数
PyObject* pFunc = PyObject_GetAttrString(pModule, "ff");
//数据准备
short* numpyptr = new short[90000000];
for (int i = 0; i < 90000000; i++)
{
short j = 1000;
numpyptr[i] = j;
}
npy_intp dims[2] = { 3000,30000 };//矩阵维度
PyObject* PyArray = PyArray_SimpleNewFromData(2, dims, NPY_SHORT, numpyptr);//将数据变为numpy
//用tuple装起来传入python
PyObject* args = PyTuple_New(1);
PyTuple_SetItem(args, 0, PyArray);
//函数调用(有返回值也是numpy
PyArrayObject* pRet = (PyArrayObject*)PyEval_CallObject(pFunc, args);
//返回的numpy矩阵的row和col
int Rows = pRet->dimensions[0], columns = pRet->dimensions[1];
cout << Rows << " " << columns << endl;
//将数据变回一般的指针
short* numpyptr2 = new short[90000000];
int j = 0;
for (int Index_m = 0; Index_m < Rows; Index_m++) {
for (int Index_n = 0; Index_n < columns; Index_n++) {
numpyptr2[j] = *(short*)(pRet->data + Index_m * pRet->strides[0] + Index_n * pRet->strides[1]);//访问数据,Index_m 和 Index_n 分别是数组元素的坐标,乘上相应维度的步长,即可以访问数组元素
j++;
}
}
cout << numpyptr2[1000] << endl;
//释放内存
Py_CLEAR(pModule);
Py_CLEAR(pFunc);
Py_CLEAR(PyArray);
Py_CLEAR(args);
Py_CLEAR(pRet);
delete[] numpyptr;
delete[] numpyptr2;
Py_Finalize(); // 释放资源
return 0;
}
Python代码:
import numpy as np
def ff(data):
print(data.shape)
print(data[0][0])
print(type(data[0][0]))
return data
利用numpy的方式不仅在传递速度上有很大的优势,并且可以与python完美的契合。
https://blog.csdn.net/qq_38232171/article/details/103955681
https://zhuanlan.zhihu.com/p/79896193
https://www.pythonf.cn/read/116854
以上是关于c++调用python脚本,指针快速传递的主要内容,如果未能解决你的问题,请参考以下文章