2017-10-04 8 views
3

長い間C++の開発者私はPythonでアルゴリズムの作業を開始しました。私は現在、コードをプロファイリングして、Pythonで効率的にプログラムする方法を感じています。特に私は専門家の説明を得ることが非常にうれしいです。Python要素のアクセス性能

私はレイ・トライアングル交差点のために、このラッパー関数を書いた:

def rayIntersectsTriangle(origin , direction , meshData , poly , worldCoordinateVertices): 
    return mathutils.geometry.intersect_ray_tri(worldCoordinateVertices[ meshData.loops[ poly.loop_start ].vertex_index ], 
               worldCoordinateVertices[ meshData.loops[ poly.loop_start + 1 ].vertex_index ], 
               worldCoordinateVertices[ meshData.loops[ poly.loop_start + 2 ].vertex_index ], 
               direction , origin) != None 

を(cProfileを使って)この関数に多くの時間を実行するコードをプロファイリングすると、私は次のような結果があります。

ncalls tottime percall cumtime percall filename:lineno(function) 
15694126 22.314 0.000 25.812 0.000 ****.py:176(rayIntersectsPoly) 
[...] 
15694126 3.497 0.000 3.497 0.000 {built-in method mathutils.geometry.intersect_ray_tri} 

このラッパーはどうしてそんなオーバーヘッドを追加しますか?私がここで実際に見ることができる唯一のことは、配列要素へのアクセスです。 C++から来て、これは私を本当に混乱させます:D

これについての助言は非常に高く評価されます。アルゴリズムをできるだけ速くしたいのですが。

ありがとうございます!乾杯!

+0

https://wiki.python.org/moin/TimeComplexity –

+0

...とbtwを参照してください。数学中心のワークロードでの実行時パフォーマンスが最重要課題である場合、Pythonはあなたのための言語ではないかもしれません。 [Julia](https://julialang.org/)や[Go](https://golang.org/)をお勧めしますか? (ベンチマークはジュリアのページの両方をカバーする)。 –

+0

素晴らしいです。リソースに感謝します。私は現在、Blenderのプラグインに取り組んでいますので、Pythonに代わるものはありません。 – Marcel

答えて

5

mathutils.geometry.intersect_ray_tri()ファストであるため、時間が大きく見えます。そのメソッドは拡張で実装され、ネイティブの速度で実行されます。 (時間が比較的大きな割合を取ることを1つの式だけで)新しい関数フレーム

  • グローバル名前検索を(これらはに対して行われて作成

    • :メソッドの

      ザ・パイソン時間がに行きますマッピング、ローカル名は配列を使用します)。 mathutils.geometrymathutils.geometry.intersect_ray_tripoly.loop_start

    • インデックス、そうworldCoordinateVertices[ ... ]よう
    • 属性検索、。

    あなたがローカル名またはデフォルトパラメータでこれらのいくつかの結果をキャッシュすることによって、少し速くそれを作ることができます:

    def rayIntersectsTriangle(
         origin, direction, meshData, poly, worldCoordinateVertices 
         _intersect_ray_tri=mathutils.geometry.intersect_ray_tri): 
        loop_start = poly.loop_start 
        meshData_loops = meshData.loops 
        return _intersect_ray_tri(
         worldCoordinateVertices[meshData_loops[loop_start].vertex_index], 
         worldCoordinateVertices[meshData_loops[loop_start + 1].vertex_index], 
         worldCoordinateVertices[meshData_loops[loop_start + 2].vertex_index], 
         direction, origin) is not None 
    

    私もis not Noneを使用。これはシングルトンNoneのテストに推奨されるポインタ操作です。

    これは約8個の属性検索をわずか2に減らし、mathutilsのグローバル名検索を削除します。

    でも、これはマイクロ最適化であり、実際に影響がある場合(例:メソッドがコードで多く呼び出されるなど)にのみ行います。これが実際にボトルネックとなっている場合は、Cythonをこのコードをネイティブスピードでも動作できるコンパイル済みエクステンションに変換するための簡単な方法として使用することを検討してください。

  • +0

    うわー、ありがとうございました。どのような詳細で高速な答え。これは間違いなく私に多くの洞察を与える – Marcel