在cython中通过cdef类属性快速排序

时间:2017-07-18 05:30:33

标签: python-2.7 cython

作为在我的2D游戏引擎中支持精灵半透明的一部分,我需要做的每一个框架之一就是从后到前按z_index属性对所有精灵进行排序(更多信息{{3 }})。目前,cdef class RenderSystem的相关骨架如下所示:

#lots of imports...

cdef class RenderSystem:

    def __init__(self):
        #other irrelevant initialization stuff here
        self.sprites = []

    def add_sprite(self, Sprite sprite):
        self.sprites.append(sprite)

    def remove_sprite(self, Sprite, sprite):
        self.sprites.remove(sprite)

    @cython.boundscheck(False)
    @cython.wraparound(False)
    @cython.initializedcheck(False)
    @cython.cdivision(True)
    @cython.infer_types(True)
    @cython.binding(False)
    def update(self):
        self.sprites.sort(key=op.attrgetter("z_index"))#op = operator
        #render-y OpenGL stuff goes here...

基本上,RenderSystem对象包含一个隐藏的cdef class Sprite对象的python隐藏列表。然后,用户可以间接地从该列表中添加或删除Sprite个对象。我的Sprite类具有cdef public float z_index属性,用户在(-1.0, 1.0]范围内设置该属性。 Sprite值较低的z_index对象会在场景中具有较高z_index值的对象后面呈现。

注释掉所有渲染代码,我意识到sort函数占用了我相当大一部分CPU使用率(13%没有渲染,> 25%(一个完整核心)渲染)。我知道在cython中,我们有一个qsort c函数可以代替使用(通过from libc.stdlib cimport qsort)。但是,在qsort here上阅读,看起来qsort只会命令传递float *z_index_list,我会失去Sprite对象之间的关联他们的z_indices

TL; DR:cython中有哪些其他更快的方法可以通过一个可以超出cpython的内置排序函数的给定属性对cdef类对象列表进行排序?

1 个答案:

答案 0 :(得分:1)

通过提高属性访问权限(而不是依赖于字典查找),您可能可以获得中等速度:

def key_func(Sprite x):
   return x.z_index

def key_func(x):
   return (<Sprite>x).z_index # this is an unsafe cast - you save time
     # by avoiding type checking, but you're relying on it to be right

我强烈考虑将sprites设置为具有复杂dtype(例如[('z_index', np.float_t), ...])的numpy数组,而不是cdef类列表。这可以通过Python访问,可以通过Cython高效访问,并且有一个fast built-in sort,允许您指定用于订单的字段。