python高性能之路:使用C/C++编写扩展

1,421 阅读2分钟

脚本语言一般使用c等静态语言编写扩展提高性能,下面使用cpp编写一个实现两数之和的python扩展函数

完成案例代码参考:1drv.ms/u/s!AquRvPz…

构建python环境

减少扩展开发对系统python的影响,建议使用venv创建一个新的python开发环境

virtualenv ~/develop/venvpy3

操作效果如下

-w482

使用命令source ~/develop/venvpy3/bin/activate激活即可

创建扩展文件sumext.cpp

sumext.cpp

#include <iostream>
#include <stdio.h>
#include <Python.h>

using namespace std;

主要是引入依赖的Python.h文件头即可,其它头文件按需引入使用

实现两数相加函数

static PyObject* sum(PyObject* Self, PyObject *args)
{
    int a, b, s;
    if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
        return NULL;
    }

    s = a + b;

    return Py_BuildValue("i", s);
}

这个函数接受两个int类型的参数,有一个int类型的返回值

函数参数解析

PyArg_ParseTuple将python脚本中传入的参数解析为cpp本地数据类型,i表示解析为int类型,两个i:"ii"表示有两个int类型的参数

支持解析的数据类型列表参考:docs.python.org/3/c-api/arg…

函数返回值定义

Py_BuildValue用于将cpp本地数据类型转为python脚本数据类型,i表示将cpp中int类型转为python脚本变量

支持解析的数据类型列表参考:docs.python.org/2.0/ext/bui…

定义函数为python扩展函数

static PyMethodDef module_methods[] = {
    {"sum", (PyCFunction) sum, METH_VARARGS, NULL},
    {NULL, NULL, 0, NULL}
};

定义扩展基础信息

static struct PyModuleDef sumext = {
    PyModuleDef_HEAD_INIT,
    "sumext",
    "extension for add two number",
    -1,
    module_methods
};

在扩展钩子中注册扩展&扩展函数

PyMODINIT_FUNC PyInit_sumext(void) {
    return PyModule_Create(&sumext);
}

PyMODINIT_FUNC PyInit_sum(void) {
    return PyModule_Create(&sumext);
}

格式:PyInit_模块名/函数名 作用:python加载模块/模块函数时的初始化函数,可以在模块/函数初始化函数中执行自定义钩子逻辑,最后返回扩展信息sumext即可

编译扩展

setup.py:

from distutils.core import setup, Extension

setup(name='sumext', version='1.0', ext_modules=[Extension('sumext', ['sumext.cpp'])])

然后使用命令python setup.py install编译,效果参考如下

-w810

使用扩展

action.py

import sumext

sum=sumext.sum(1, 2)

print("Sum is :", sum)

然后使用命令python action.py执行,执行效果如下:

-w336

可以看到扩展已经成功加载执行了

参考资料

  1. docs.python.org/3/extending…
  2. docs.python.org/3/extending…
  3. www.tutorialspoint.com/python/pyth…
  4. docs.python.org/3/c-api/arg…