【翻译】Cython教程7_Cython加速之早期绑定机制(early binding)

原创文章,转载请注明: 转载自勤奋的小青蛙
本文链接地址: 【翻译】Cython教程7_Cython加速之早期绑定机制(early binding)

作为一种动态语言,Python鼓励使用一种编程风格,根据其方法和属性来考虑类和对象,而不是它们适合于类层次结构。

这可以使Python成为一种非常轻松和舒适的语言,用于快速开发,但是有一个代价 - 管理数据类型的“繁文。节”被转储到翻译器上。在运行时,解释器在搜索命名空间,获取属性和解析参数和关键字元组方面做了大量工作。与“早期绑定”语言(如C ++)相比,这种运行时“后期绑定”是Python相对较慢的主要原因。

然而使用Cython可以通过使用“早期绑定”编程技术获得显着的加速。

例如,考虑以下(愚蠢)代码示例:

cdef class Rectangle:
    cdef int x0, y0
    cdef int x1, y1
    def __init__(self, int x0, int y0, int x1, int y1):
        self.x0 = x0; self.y0 = y0; self.x1 = x1; self.y1 = y1
    def area(self):
        area = (self.x1 - self.x0) * (self.y1 - self.y0)
        if area < 0:
            area = -area
        return area

def rectArea(x0, y0, x1, y1):
    rect = Rectangle(x0, y0, x1, y1)
    return rect.area()

在rectArea()方法中,对rect.area()和area()方法的调用包含大量的Python开销。

然而,在Cython中,可以在Cython代码中发生调用的情况下消除大量的这种开销。例如:

cdef class Rectangle:
    cdef int x0, y0
    cdef int x1, y1
    def __init__(self, int x0, int y0, int x1, int y1):
        self.x0 = x0; self.y0 = y0; self.x1 = x1; self.y1 = y1
    cdef int _area(self):
        cdef int area
        area = (self.x1 - self.x0) * (self.y1 - self.y0)
        if area < 0:
            area = -area
        return area
    def area(self):
        return self._area()

def rectArea(x0, y0, x1, y1):
    cdef Rectangle rect
    rect = Rectangle(x0, y0, x1, y1)
    return rect._area()

这里,在Rectangle扩展类中,我们定义了两个不同的区域计算方法,即有效的_area()C方法和Python-callable area()方法,它们作为_area()周围的一个薄包装。注意在函数rectArea()中,我们如何通过声明明确给出类型Rectangle的局部变量rect来“早期绑定”。通过使用此声明,而不是仅仅动态分配给rect,我们获得了访问更高效的C-callable _area()方法的能力。

但是,Cython再次为我们提供了更多的简单性,通过允许我们声明双重访问方法 - 可以在C级高效调用的方法,但也可以以纯Python代码访问,代价是Python访问开销。考虑这个代码:

cdef class Rectangle:
    cdef int x0, y0
    cdef int x1, y1
    def __init__(self, int x0, int y0, int x1, int y1):
        self.x0 = x0; self.y0 = y0; self.x1 = x1; self.y1 = y1
    cpdef int area(self):
        cdef int area
        area = (self.x1 - self.x0) * (self.y1 - self.y0)
        if area < 0:
            area = -area
        return area

def rectArea(x0, y0, x1, y1):
    cdef Rectangle rect
    rect = Rectangle(x0, y0, x1, y1)
    return rect.area()

注意:在Cython的早期版本中,cpdef关键字是rdef - 但具有相同的效果)。

在这里,我们只有一个单一的区域方法,被声明为cpdef,使其有效地被称为C函数,但仍然可以从纯Python(或后期绑定的Cython)代码访问。

如果在Cython代码中,我们有一个已经“早期绑定”的变量(即,明确声明为Rectangle类型,或者转换为Rectangle类型),那么调用其区域方法将使用高效的C代码路径并跳过Python开销。但是,如果在Pyrex或普通的Python代码中,我们有一个存储Rectangle对象的常规对象变量,那么调用area方法将需要:

  • 区域方法的属性查找
  • 包装一个元组的参数和一个关键字的dict(在这种情况下都是空的)
  • 使用Python API调用的方法

并在区域方法本身内:

  • 解析元组和关键字
  • 执行计算代码
  • 将结果转换为python对象并返回

所以在Cython中,可以通过在声明和转换变量中使用强类型来实现大量的优化。对于使用方法调用的紧密循环,这些方法是纯C语言实现的,相比Python语言,运行速度可是绝对占优势的。

原创文章,转载请注明: 转载自勤奋的小青蛙
本文链接地址: 【翻译】Cython教程7_Cython加速之早期绑定机制(early binding)

文章的脚注信息由WordPress的wp-posturl插件自动生成



|2|left
打赏

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: