作为在我的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类对象列表进行排序?
答案 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,允许您指定用于订单的字段。