2017-07-18 17 views
0

2Dゲームエンジンでサポートされているスプライトの半透明性の一部として、フレームごとに行う必要があることの1つは、z_indexプロパティですべてのスプライトを並べ替えることです情報here)。次のように現在、私のcdef class RenderSystemに関連する骨格が見えます:cythonのcdefクラスプロパティによる高速ソート

#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クラスは、ユーザーが(-1.0, 1.0]の範囲で設定するcdef public float z_indexプロパティを持っています。 Spritez_indexの値を持つオブジェクトは、シーン内でより高い値のz_indexを持つオブジェクトの背後に表示されます。

sort機能だけでは、CPU使用量のかなりの部分(レンダリングなしで13%、レンダリングで> 25%(フルコア))が実現したことに気付きました。私はcythonで、代わりに(from libc.stdlib cimport qsort経由で)使用できるqsort c関数があることを知っています。しかし、qsorthereを読むと、それはのように見えます。それはfloat *z_index_listで渡されたものを注文し、Spriteオブジェクトとそのz_indicesの間の関連付けを失います。

TL; DR:cpythonの組み込みソート関数を実行できない特定の属性によってcdefクラスオブジェクトのリストをソートするための、いくつかの方法があります。

答えて

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 

私は」 dは、spritesを、cdefクラスのリストではなく、複雑なdtype(例:[('z_index', np.float_t), ...])のnumpy配列にすることを強く検討します。これはPythonからアクセス可能で、Cythonを通じて効率的にアクセスできます。fast built-in sortを使用すると、注文に使用するフィールドを指定できます。

+0

いつものようにありがとう!あなたの 'key_func'を使っていくつかのCPU%を削りました(今は9%はレンダリングなし、同じ25%はレンダリングで)。代わりにnumpyを使用するようにコードを再構築しようとします。私が気が狂ったルートに行くと、これは私の 'Sprite'クラスをそのまま保つことができますか?私の 'Sprite'クラスは多くの数値プロパティと固定サイズの浮動小数点配列を持っていますが、OpenGLと大きく相互作用する' Texture'クラスにも依存しています。私はおそらく、これらのオブジェクト( 'Sprite'オブジェクトとその子' Texture')へのuint32_tポインタをnumpy配列に格納することを考えていました。 – CodeSurgeon

+1

他のPython/Cythonクラスへのポインタを格納している場合は、おそらく良いソリューションではありません。 – DavidW

+0

ちょうど好奇心からnumpyを試してみましたが、ソートのパフォーマンスは 'key_func'とほぼ同じですが、スプライトの追加と削除(特に)は遅いです(配列が固定サイズであるため、要素を中間に追加し、最後に新しい要素を追加して配列内の「穴」を避ける)。その他の提案はありますか? – CodeSurgeon

関連する問題