美文网首页
python加速--如何调用C/C++代码

python加速--如何调用C/C++代码

作者: chaos_chen | 来源:发表于2019-01-25 15:33 被阅读0次

    python加速--如何调用C/C++代码

    前言

    普通python代码的速度大概要比C++慢上100倍。(benchmark参考)
    当然python的很多常用库都是调用so,而且是经过优化的,比如numpy,其矩阵运算比起自己写的c++代码还快(通过BLAS加速)。
    我们实际在不多的情况下(比如自己定义的一些算法),才需要改写成C++提高性能。

    下面介绍几种常见的python调用C++的方式:

    boost-python

    boost-python不需要改变原有的C++代码,不会生成额外的python代码,所需要的就是定义好python需要调用到的C++的接口,然后写少量的boost-python的C++封装代码。

    • 安装
    sudo ./b2 --with-python install
    
    • 编译boost
    b2  --with-python  test_dir/  -sBOOST_ROOT=~/boost_1_68_0
    

    注意:mac上cmake和boost版本不匹配可能会遇到链接问题,最好使用boost-python1.66以上版本,要把cmake版本更新到3.12.3以上。

    • test.hpp
      以最简单的打印字符串举例:
    #include <string>
    class ClassA{
        public:
            ClassA();
            ~ClassA();
            DoSomething(std::string p){cout<<p};
    }
    
    • test.cpp
      封装代码主要做模块声明、声明类和作为api调用的成员函数
      这里的声明很简单,都不用管函数的参数和返回类型;如果类初始化需要参数可以把参数写进py::init<>里面
    #include "test.hpp"
    #include <boost/python.hpp>
    namespace np = boost::python::numpy;
    
    BOOST_PYTHON_MODULE(Module_Name){   
        np::initialize();
    
        py::class_<ClassA, boost::noncopyable>("ClassA", py::init<>())
            .def("DoSomething", &ClassA::DoSomething)
        ;
    }
    
    • test.py
    from Module_Name import Module_Name
    c = Module_Name.ClassA()
    c.DoSomething("hello world")
    
    • CMakeList.txt
    cmake_minimum_required(VERSION 2.8.3)
    
    project(Module_Name)
    
    find_package( PythonInterp 2.7 REQUIRED )
    find_package( PythonLibs 2.7 REQUIRED )
    find_package( Boost COMPONENTS python27 system numpy27 atomic date_time exception REQUIRED)
    
    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
    
    set(Boost_USE_STATIC_LIBS OFF)
    set(Boost_USE_MULTITHREADED ON)
    set(Boost_USE_STATIC_RUNTIME OFF)
    
    INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS})
    PYTHON_ADD_MODULE(${PROJECT_NAME} xxxxx.cpp )
    
    target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES} ${PYTHON_LIBRARIES})
    
    • 编译
    cmake ./  && make
    
    • 运行
    python test.py
    

    参考

    复杂的boost-python封装代码可参考这里,比如如何使用成员变量、继承、虚函数等。

    swig

    swig(Simplified Wrapper and Interface Generator )支持多种语言调用C/C++。通过定义一个接口文件(.i文件),生成中间的python代码和C++代码(是的,两种代码都会生成),并生成.so。
    还是以简单的"hello world举例":

    • test.cpp
    #include "test.h"
    
    int DoSomething(const char* text)
    {
        std::cout<<text;
        return 0;
    }
    
    • test.h
    #include <iostream>
    
    int DoSomething(const char *text);
    
    • test.i
    %module test
    %{
    #define SWIG_FILE_WITH_INIT
    #include "test.h"
    %}
    
    %include "test.h"
    

    最重要的就是这个“test.i”,注意这里有两个地方包括“test.h”,不可省略。
    第一个是告诉swig生成的中间c++代码需要它。
    第二个是告诉swig生成的中间python代码需要它(也就是哪些函数通过借口封装在so中)。

    • 编译
    python setup.py build
    
    • 运行
      注意PYTHONPATH要包含生成的_test.so路径
    python
    import test
    test.DoSomething("Hello World")
    

    总结

    还有其他的python调用C的方式,比如ctype、cython,感觉都不好用,相当于重新学了个新语言,需要了解较多的相关库知识。
    对于比较熟悉C++的人来说还是boost-python比较方便,是用C++的方式来主导项目,生成的中间文件比较少,容易切分C++程序员和python程序员的任务。

    相关文章

      网友评论

          本文标题:python加速--如何调用C/C++代码

          本文链接:https://www.haomeiwen.com/subject/dwxujqtx.html