cython理解(一)

之前和大家简单介绍过一些cython的简单使用方法,显然只了解这些在大型的工程中为c++封装Python可以调用的动态库是远远不够的。举一个很简单的例子,众所周知,Python和c++的很多的特性是不一样的,比如说Python中你赋值给变量a为1,实际的计算机中变量a的位宽是64位,而在c++中这个变量可能只有32位,所以本身来说为Python编写动态库相对而言是一件非常危险的事情:比如你处理一个int *指针,原先的c++程序直接指针++就可以,但是如果说Python的存储位宽是64,你没有办法,你只能把原先c++程序的int指明为64位宽的int64_t,因为只有这样你的程序才是正确的。
下面我将和大家分享一个简单的例子:Python程序中有一大坨数(很多个),我让每个数都在原来的基础上+100,很明显这个程序可以并行来计算,我们在c++中使用cuda并且为Python封装程动态库供Python可以快速提高运行效率。demo程序已经同步到github(https://github.com/zhangjiaxinghust/cpp_warp_python_demo )。

程序可以分为4层

在整个程序框架中,我们想一下cython是怎么能够让Python调用c++的函数的呢?

  1. 必须将Python提供给c++的函数参数转为c++程序可以访问的数据格式;同时,c++函数的返回值也要对应转换为Python程序可以访问的格式。
    举一个简单的例子:c++函数返回了两个参数(int *ptr, int n),如何让Python访问呢?
cdef convert_to_python(int *ptr, int n):
    cdef int i
    lst=[]
    for i in range(n):
        lst.append(ptr[i])
    return lst
    
def get_value():
    pointer = XXXX(XXXX可以认为是一个函数返回了一个int *指针)
    length = XXXX
    return convert_to_python(pointer,length)

按照上述定义我们可以很简单的理解了:我一个c++的变量是不能够直接提供给Python使用的,他必须要经过一些转换,同理呢,Python的变量也必须要进行一些转换,只有这些转换做完了才可以相互通信。
2. 为什么说可以分为4层?
大家可以在上面的例子中很简单的看到:两个函数声明时所用的关键字是不一样的:def和cdef,他们有什么差别呢?可以简单的这样理解:def定义的函数是封装后的so暴露给Python可以调用的接口,而cdef仅仅是cython程序内部可以使用的,Python程序不可以调用。比如我上面定义的函数convert_to_python,看一眼它的函数参数有一个int *这个参数很明显Python是无法提供的,Python无论如何也无法直接在程序中提供一个int*类型的变量。根据这个我们他们简单分为4层。

c++程序
c++接口:cython中声明c++程序的接口和cdef定义的其他函数
Python接口:def定义的函数
Python程序

看到这四层,我们对cython的运行也有了一些了解,c++程序写好了有很多函数,我必须要在cython中做一些声明,参考例子demo_dynamic(github),里面有文件rect.pxd

# distutils: language = c++
# Declare the class with cdef
cdef extern from "Rectangle.h" namespace "shapes":
    cdef cppclass Rectangle:
        Rectangle() except +
        Rectangle(int, int, int, int) except +
        int x0, y0, x1, y1
        int getArea()
        void getSize(int* width, int* height)
        void move(int, int)

这个文件就是用来声明c++的函数和类,c++里面写了很多很多的函数,但是只有声明了才可以在cython中使用,不声明就不能够使用。但是这些函数声明了仅仅只是在cython中可以使用,Python中依然无法使用,我们还需要cython中编写可以供Python调用的接口。于是我们看rect.pyx:

# distutils: language = c++

from Rectangle cimport Rectangle

cdef class PyRectangle:
    cdef Rectangle c_rect

    def __cinit__(self, int x0, int y0, int x1, int y1):
        self.c_rect = Rectangle(x0, y0, x1, y1)

    def get_area(self):
        return self.c_rect.getArea()

    def get_size(self):
        cdef int width, height
        self.c_rect.getSize(&width, &height)
        return width, height

    def move(self, dx, dy):
        self.c_rect.move(dx, dy)

我们在该文件中定义了一个可以供Python调用的类,并且为这个类编写了很多Python可以调用的函数,在这个类中声明了一个对象,函数也全部调用这个对象的接口。到这里之后,我们在Python中就可以使用类PyRectangle了,也可以使用类调用的各种函数了。
更多细节可以参考上一篇博文(cython简单使用方法)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jiaxing.Zhang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值