私の問題:STLマップとベクターを使用して生のC++で大規模なデータセットを処理すると、Cythonを使用するよりもかなり高速になる(メモリフットプリントが小さい)ことがよくあります。
この速度ペナルティの一部はPythonリストとdictを使用することによるものであり、Cythonで邪魔にならないデータ構造を使用するためのいくつかのトリックがあるかもしれないと思います。たとえば、このページ(- http://wiki.cython.org/tutorials/numpy )は、ND配列のサイズとタイプを事前に定義することにより、Cythonでnumpy配列を非常に高速にする方法を示しています。
質問:リスト/ディクテーションで同様のことを行う方法はありますか?それらに含まれると予想される要素または(キー、値)ペアの大まかな数を述べることによって? つまり、Cythonでリスト/ディクテーションを(高速)データ構造に変換する慣用的な方法はありますか?
そうでない場合は、C++で記述し、Cythonインポートでラップする必要があると思います。
Cythonはテンプレートをサポートするようになり、一部のSTLコンテナーの宣言が付属しています。
http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html#standard-library を参照してください
彼らが与える例は次のとおりです。
from libcpp.vector cimport vector
cdef vector[int] vect
cdef int i
for i in range(10):
vect.Push_back(i)
for i in range(10):
print vect[i]
PythonでC++と同様の操作を行うと、処理が遅くなることがよくあります。list
とdict
は実際には非常にうまく実装されていますが、=を使用すると多くのオーバーヘッドが発生します。 Pythonオブジェクト。C++オブジェクトよりも抽象的で、実行時にさらに多くのルックアップが必要です。
ちなみに、std::vector
はlist
と非常によく似た方法で実装されています。ただし、std::map
は、実際には、サイズが大きくなるにつれて、多くの操作がdict
よりも遅くなるように実装されています。それぞれの適切に大きな例の場合、dict
は、std::map
よりも遅い定数係数を克服し、実際にはルックアップ、挿入などの操作をより速く実行します。
std::map
とstd::vector
を使用したい場合、何もあなたを止めません。 Pythonに公開する場合は、自分でラップする必要があります。このラッピングが節約したいと思っていた時間のすべてまたは多くを費やしても、ショックを受けないでください。私はあなたのためにこれを自動化するツールを知りません。
オブジェクトの作成を詳細に制御するためのCAPI呼び出しがあります。 「少なくともこれだけ多くの要素を含むリストを作成する」と言うことはできますが、これによってリストの作成と入力の操作の全体的な複雑さが改善されるわけではありません。リストを変更しようとしても、後で変更されることはありません。
私の一般的なアドバイスは
固定サイズの配列が必要な場合(リストのサイズを指定することについて話します)、実際にはnumpy配列のようなものが必要になる場合があります。
コード内の一般置換にlist
よりもstd::vector
を使用することで、必要なスピードアップが得られるとは思えません。舞台裏で使用したい場合は、満足のいくサイズとスペースの改善が得られる可能性があります(もちろん、測定せずにはわかりません。;))。
dict
は実際にその仕事を本当にうまくやっています。 Python std::map
に基づく)で使用するための新しい汎用タイプを導入しようとは絶対にしません。これは、多くの重要な操作に間に合うようにアルゴリズムの複雑さが悪化します。少なくともいくつかの実装— dict
がすでに持っているいくつかの最適化をユーザーに任せます。
std::map
のようにもう少し機能するものが必要な場合は、おそらくデータベースを使用します。これは通常、dict
に保存したいもの(または、さらに言えば、list
に保存したもの)が大きくなりすぎて、メモリに快適に保存できない場合に行うことです。 Python stdlibと利用可能な他のすべての主要データベースのドライバーにsqlite3
があります。
C++は、ベクトルとそれに含まれる要素の静的宣言のためだけでなく、テンプレート/ジェネリックを使用して、ベクトルにのみの要素が含まれるように指定するため、高速です。特定のタイプ、例えば3つの要素のタプルを持つベクトル。 Cythonはこの最後のことを行うことができず、些細なことではないように聞こえます-どういうわけか、コンパイル時に強制する必要があります(実行時のタイプチェックはPythonはすでに行っています)。 Cythonのリストから何かをポップすると、それがどのタイプであるかを事前に知る方法はなく、型付き変数に入れると、速度ではなくタイプチェックが追加されるだけです。これは、Pythonインタープリターであり、数値以外のタスクに対するCythonの最も重大な欠点であるように思われます。
これを手動で解決する方法は、python list/dict(またはおそらくstd :: vector)を特定のタイプの要素またはキーと値の組み合わせのcdefクラスでサブクラス化することです。テンプレートが生成しているコードと同じものに。Cythonコードで結果のクラスを使用する限り、それは改善を提供するはずです。
データベースまたは配列を使用すると、別の問題が解決されます。これは、任意のオブジェクト(ただし、特定のタイプ、できればcdefクラス)をコンテナーに配置するためです。
そして、std :: mapはdictと比較されるべきではありません。 std :: mapはバランスの取れたツリーであるため、ソートされた順序でキーを維持します。dictは別の問題を解決します。より良い比較は、dictとGoogleのハッシュテーブルです。
標準の array
モジュールをPythonの場合、これがCythonの設定に適しているかどうかを確認できます。 Cythonを使用したことはありません。
ネイティブPythonリスト/ディクテーションをC++マップ/ベクターの速度まで、またはそれに近い場所でさえも取得する方法はありません。割り当てや型宣言とは関係ありませんが、インタプリタに支払います。あなたが言及した例(numpy)はC拡張であり、まさにこの理由でCで書かれています。