如何使用python和C、C++混编提高执行速度

前言:python的开发效率高,但是运行效率低是大家都知道,特别在对列表进行读写操作时,有时候就无法忍受。除了使用numpy进行操作外,还有一些方法可以提高运行效率。

一、使用cypes

我们可以使用c、c++写好一个库文件。下面以linux中的操作为例(windows类似)

写一个C文件

#include 
#include 
void helloWorld(){
    printf("Hello world\n");
}
int plus(int x){
    return x+1;
}

然后使用gcc编译成动态链接库

gcc hello.c -shared -fpic -o hello.so -lm

python代码如下

import ctypes
libc=ctypes.cdll.LoadLibrary(\"./CFile/hello.so\")
libc.helloWorld()
print(libc.plus(3))

这样,就能够简单地传个整数计算或者执行一些底层操作。
有一点注意的是,使用g++编译成动态链接库的时候,C++代码的方法名称和链接库里面的名称不尽相同,可以通过

nm hello.so

查看连接库对应方法的名称
如何使用python和C、C++混编提高执行速度_第1张图片
但是这个方法有个bug,不能够传浮点数或者返回浮点数,也不能传列表等对象
还有一个方法。

二、使用numpy

我在使用opencv+python写运行在raspberry上面的代码时,有一个简单粗暴的算法,就是遍历一次一个二值化图像,找出每一行白色区域的连续最大长度,使用python在手提上面运行都要1s,这是无法接受的。这就要寻找更好的方法来实现。

使用ctypes混编是无法传一个opencv mat对象进去的,于是我看到一份代码
https://github.com/yushulx/opencv-python-webcam-barcode-reade
于是我就参考着,简化了一下代码,粗略估计,在手提上测试这一份暴力代码,速度提升了500倍,
首先构造一个python c库的基本结构要有

//method to be registered
static PyMethodDef Methods[] ={
     {\"printBinImgBits\", printBinImgBits, METH_VARARGS, NULL},
     {NULL, NULL, 0, NULL}
};

//initilize function
PyMODINIT_FUNC
initPrintBinImgBits(void){
     printf(\"PrintBinImgBits Init\\n\");
	(void) Py_InitModule(\"PrintBinImgBits\", Methods);
}

python import这个库的时候会执行initPrintBinImgBits初始化。然后在初始化的时候应该注册可以被python调用的方法(我猜是这样的)。然后就写方法

#include 
#include 
#include 
static PyObject * printBinImgBits(PyObject *self, PyObject *args) {
    PyObject *o;
    if (!PyArg_ParseTuple(args, \"O\", &o))
        return NULL;

    PyObject *ao = PyObject_GetAttrString(o, \"__array_struct__\");

    PyArrayInterface *pai = (PyArrayInterface*)PyCObject_AsVoidPtr(ao);


    char *buffer = (char*)pai->data; // The address of image data
    int width = pai->shape[1];       // image width
    int height = pai->shape[0];      // image height
    int size = pai->strides[0] * pai->shape[0]; // image size = stride * height
    int stride = pai->strides[0];

    for(int j=0;j

然后还有写一个python setup文件,编译安装这个库

from distutils.core import setup, Extension

mModule = Extension(\'PrintBinImgBits\',

sources= [\'PrintBinImgBits.c\'],

include_dirs=[\"/usr/lib/python2.7/dist-packages/numpy/core/include/numpy\"],

library_dirs=[],

libraries=[])

setup (name = \'PrintBinImgBits\',

version=\'1.0\',

description=\'Python PrintBinImgBits extension\',

ext_modules= [mModule])

执行

sudo python setup.py build install

即可安装这个库到 /usr/local/lib/python2.7/dist-packages/ 下
然后调用就简单了

import PrintBinImgBits
import cv2
import numpy as np

img=cv2.imread(\"test.jpg\")
grayImg=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
binImg=cv2.inRange(grayImg,np.array([128]),np.array([255]))
PrintBinImgBits.printBinImgBits(binImg)

执行代码,就会输出图像的二值化像素点,(RGB彩图我没试过,应该大致一样)

如何从C代码里面返回一个列表或者其他对象

PyObject* retval = Py_BuildValue("i", 666)

返回列表为例,改成

PyObject *retval=PyList_New(count);

写入列表即

PyList_SetItem(retval, j, Py_BuildValue("i",x));

调用模块,即可返回一个列表
代码地址:
https://github.com/HeroChan0330/Python-hybrid-compile-with-c
这篇加上后面三篇博客都是从我的wordpress上面搬过来了(因为服务器到期了,卑微),可能会有点细节问题)

你可能感兴趣的:(如何使用python和C、C++混编提高执行速度)