39

私の問題:STLマップとベクトルを使用して生のC ++で大規模なデータセットを処理すると、Cythonを使用するよりもかなり高速になることがよくあります(メモリフットプリントが少なくなります)。

この速度のペナルティの一部は、Pythonリストとdictを使用することによるものであり、Cythonで邪魔にならないデータ構造を使用するためのトリックがあるかもしれないと思います。たとえば、このページ(http://wiki.cython.org/tutorials/numpy)は、ND配列のサイズとタイプを事前に定義することにより、Cythonでnumpy配列を非常に高速にする方法を示しています。

質問:リスト/ディクテーションで同様のことを行う方法はありますか?たとえば、それらに含まれると予想される要素または(キー、値)ペアの大まかな数を示すことによってですか?つまり、Cythonでリスト/ディクテーションを(高速な)データ構造に変換する慣用的な方法はありますか?

そうでない場合は、C ++で記述し、Cythonインポートでラップする必要があると思います。

4

6 に答える 6

37

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]
于 2011-12-14T17:09:26.567 に答える
34

PythonでC++と同様の操作を行うと、処理が遅くなることがよくあります。list実際にdictは非常にうまく実装されていますが、Pythonオブジェクトを使用すると多くのオーバーヘッドが発生します。PythonオブジェクトはC ++オブジェクトよりも抽象的であり、実行時にさらに多くのルックアップが必要です。

ちなみに、std::vectorはと非常によく似た方法で実装されていlistます。std::mapただし、実際にはdict、サイズが大きくなるよりも多くの操作が遅くなるように実装されています。それぞれの適切に大きな例では、dictそれがより遅いという一定の要因を克服し、std::map実際にはルックアップ、挿入などの操作をより速く実行します。

std::mapとを使用したい場合std::vectorは、何もあなたを止めていません。Pythonに公開する場合は、自分でラップする必要があります。このラッピングが節約したいと思っていた時間のすべてまたは多くを費やしても、ショックを受けないでください。私はあなたのためにこれを自動化するツールを知りません。

オブジェクトの作成を詳細に制御するためのCAPI呼び出しがあります。「少なくともこれだけ多くの要素を含むリストを作成する」と言うことはできますが、これによってリストの作成と入力の操作の全体的な複雑さが改善されるわけではありません。リストを変更しようとしても、後で変更されることはありません。

私の一般的なアドバイスは

  • 固定サイズの配列(リストのサイズを指定することについて話します)が必要な場合は、実際にはnumpy配列のようなものが必要になる場合があります。

  • コードの一般的なstd::vector置き換えに使用することで、必要なスピードアップが得られるとは思えません。舞台裏で使用したい場合は、満足のいくサイズとスペースの改善が得られる可能性があります(もちろん、測定せずにわかりません。;))。list

  • dict実際にその仕事は本当にうまくいきます。に基づいてPythonで使用するための新しい汎用タイプを導入しようとは絶対にしませんstd::map。これは、多くの重要な操作に間に合うようにアルゴリズムの複雑さが悪化し、少なくとも一部の実装では、dictすでに持っているユーザーにいくつかの最適化を任せます。

    もう少し機能するものが必要な場合はstd::map、おそらくデータベースを使用します。これは一般的に、私が保存したいものdict(または、さらに言えば、私が保存するものlist)が大きくなりすぎて、メモリに快適に保存できない場合に行うことです。Pythonにはsqlite3、利用可能な他のすべての主要なデータベースのstdlibとドライバーがあります。

于 2010-04-23T14:58:39.677 に答える
9

C ++は、ベクトルとそれに含まれる要素の静的宣言だけでなく、テンプレート/ジェネリックを使用して、ベクトルに特定のタイプの要素のみが含まれるように指定するため、高速です。たとえば、3つの要素のタプルを持つベクトルです。Cythonはこの最後のことを行うことができず、些細なことではないように聞こえます。コンパイル時に強制する必要があります(実行時のタイプチェックはPythonがすでに行っていることです)。したがって、現時点でCythonのリストから何かをポップするとき、それがどのタイプであるかを事前に知る方法はありません。それを型付き変数に入れると、速度ではなくタイプチェックが追加されるだけです。これは、この点でPythonインタープリターをバイパスする方法がないことを意味し、数値以外のタスクに対するCythonの最も重大な欠点であるように思われます。

これを手動で解決する方法は、特定のタイプの要素またはキーと値の組み合わせのcdefクラスを使用してpython list / dict(またはおそらくstd :: vector)をサブクラス化することです。これは、テンプレートが生成しているコードと同じことになります。結果のクラスをCythonコードで使用する限り、改善が見られるはずです。

データベースまたは配列を使用すると、別の問題が解決されます。これは、任意のオブジェクト(ただし、特定のタイプ、できればcdefクラス)をコンテナーに配置することに関するものだからです。

そして、std::mapはdictと比較されるべきではありません。std :: mapはバランスの取れたツリーであるため、ソートされた順序でキーを維持します。dictは別の問題を解決します。より良い比較は、dictとGoogleのハッシュテーブルです。

于 2011-05-26T13:55:00.383 に答える
3

arrayCythonの設定に適している場合は、Pythonの標準モジュールを確認できます。Cythonを使ったことがないのでわかりません。

于 2009-10-10T03:57:11.497 に答える
0

ネイティブPythonリスト/ディクテーションをC++マップ/ベクターの速度まで、またはそれに近い場所で取得する方法はありません。割り当てや型宣言とは何の関係もありませんが、インタプリタのオーバーヘッドを支払うことになります。あなたが言及する例(numpy)はC拡張であり、まさにこの理由でCで書かれています。

于 2009-10-10T04:38:32.640 に答える
0

ここで言及されていないという理由だけで、たとえばC++ベクトルをカスタム拡張タイプで簡単にラップできます。

from libcpp.vector cimport vector

cdef class pyvector:
    """Extension type wrapping a vector"""
    cdef vector[long] _data

    cpdef void push_back(self, long x):
        self._data.push_back(x)

    @property
    def data(self):
        return self._data

このようにして、データをベクターに格納し、Python側からデータに(ある程度のオーバーヘッドを付けて)アクセスしながら、Cythonの高速操作を可能にすることができます。

于 2020-05-25T19:04:05.877 に答える