22

私はしばらくの間、ピーク フィッティング ライブラリの作成について熟考してきました。私は Python をかなりよく知っており、最初はすべてを Python で実装する予定ですが、最終的にはコンパイル済み言語でいくつかのコア ルーチンを再実装する必要があるかもしれないと考えています。

IIRC は、Python の元の任務の 1 つで、プロトタイピング言語でした。ただし、Python は、関数、ファンクター、オブジェクトを関数やメソッドに渡すことを許可する点でかなり自由ですが、C や Fortran については同じことが当てはまらないのではないかと思います。

コンパイルされた言語にインターフェースする必要があると予想される関数/クラスの設計について何を知っておくべきですか? また、これらの潜在的な問題のうち、cTypes、bgen、 SWIGBoost.PythonCythonPython SIPなどのライブラリによってどの程度対処されているのでしょうか?

この特定のユース ケース (フィッティング ライブラリ) では、ユーザーが数学関数 (Guassian、Lorentzian など) を Python 関数として定義し、コンパイルされたコード フィッティング ライブラリによって解釈されて渡されるようにすることを想像します。配列の受け渡しも不可欠です。

4

7 に答える 7

36

最後に、私が本当に価値のある答えを出すことができる質問:)。

私は自分の仕事のためにf2py、boost.python、swig、cython、pyrexを調査しました(光学測定技術の博士号)。私はswigを広範囲に使用し、boost.pythonをいくつか使用し、pyrexとcythonを多く使用しました。ctypesも使用しました。これは私の内訳です:

免責事項:これは私の個人的な経験です。私はこれらのプロジェクトには関与していません。

swig: c++ではうまく機能しません。そうすべきですが、リンク手順での名前マングリングの問題は、LinuxとMac OS Xでの私にとって大きな頭痛の種でした。Cコードがあり、Pythonに接続したい場合は、それが良い解決策です。私は自分のニーズに合わせてGTSをラップし、基本的に接続可能なC共有ライブラリを作成する必要がありました。私はそれをお勧めしません。

Ctypes: ctypesを使用してlibdc1394(IEEE Camera library)ラッパーを作成しましたが、これは非常に簡単な体験でした。コードはhttps://launchpad.net/pydc1394にあります。ヘッダーをPythonコードに変換するのは大変な作業ですが、すべてが確実に機能します。これは、外部ライブラリとのインターフェースをとる場合に適した方法です。Ctypesもpythonのstdlibに含まれているため、誰でもすぐにコードを使用できます。これは、Pythonで新しいlibをすばやく試すための良い方法でもあります。外部ライブラリへのインターフェイスに推奨できます。

Boost.Python:とても楽しいです。Pythonで使用したい独自のC++コードがすでにある場合は、これを使用してください。この方法で、C++クラス構造をPythonクラス構造に変換するのは非常に簡単です。Pythonで必要なc++コードがある場合は、これをお勧めします。

Pyrex / Cython: PyrexではなくCythonを使用してください。限目。Cythonはより高度で、より楽しく使用できます。今日、私はSWIGやCtypesで行っていたcythonですべてを行っています。実行速度が遅すぎるPythonコードがある場合にも最適な方法です。プロセスは絶対に素晴らしいです:あなたはあなたのpythonモジュールをcythonモジュールに変換し、それらを構築し、それがまだpythonであったようにプロファイリングと最適化を続けます(ツールの変更は必要ありません)。次に、Pythonコードと混合したCコードをできるだけ多く(または少しだけ)適用できます。これは、アプリケーションのすべての部分をCで書き直すよりもはるかに高速です。内側のループを書き直すだけです。

タイミング:ctypesの呼び出しオーバーヘッドが最も高く(〜700ns)、次にboost.python(322ns)、次に直接swig(290ns)が続きます。Cythonは、呼び出しのオーバーヘッドが最も低く(124ns)、時間を費やす場所でのフィードバックが最も優れています(cProfileサポート!)。数値は、インタラクティブシェルから整数を返す簡単な関数を呼び出す私のボックスからのものです。したがって、モジュールのインポートオーバーヘッドはタイミングが設定されておらず、関数呼び出しのオーバーヘッドのみがタイミング設定されています。したがって、cythonをプロファイリングして使用することにより、Pythonコードを高速に取得するのが最も簡単で生産的です。

要約:問題については、Cythonを使用してください;)。この要約が一部の人々に役立つことを願っています。残りの質問には喜んでお答えします。


編集:言及するのを忘れています:数値的な目的(つまり、NumPyへの接続)にはCythonを使用します。彼らはそれをサポートしています(基本的にこの目的のためにcythonを開発しているため)。したがって、これはあなたの決定のための別の+1になるはずです。

于 2009-11-02T13:16:20.447 に答える
10

私は SWIG や SIP を使用したことはありませんが、boost.pythonを使用して Python ラッパーを作成すると、非常に強力で比較的使いやすいことがわかります。

C/C++ と python の間で型を渡すための要件が​​何であるかは明確ではありませんが、C++ 型を python に公開するか、汎用的なboost::python::object引数を使用することで簡単に行うことができますC++ API。コンバーターを登録して、python 型を C++ 型に、またはその逆に自動的に変換することもできます。

boost.python を使用する予定がある場合は、チュートリアルを開始するのに適しています。

私はあなたが必要とするものに幾分似たものを実装しました。Python 関数と画像を引数として受け取り、Python 関数を画像の各ピクセルに適用する C++ 関数があります。

Image* unary(boost::python::object op, Image& im)
{
    Image* out = new Image(im.width(), im.height(), im.channels());
    for(unsigned int i=0; i<im.size(); i++)
    {
        (*out)[i] == extract<float>(op(im[i]));
    }
    return out;
}

この場合、Image は Python に公開された C++ オブジェクト (float ピクセルを含む画像) であり、op は Python で定義された関数 (または実際には __call__ 属性を持つ任意の Python オブジェクト) です。次に、この関数を次のように使用できます (単項が、Image と load 関数も含む呼び出されたイメージにあると仮定します)。

import image
im = image.load('somefile.tiff')
double_im = image.unary(lambda x: 2.0*x, im)

ブーストで配列を使用することに関しては、私は個人的にこれを行っていませんが、ブーストを使用して配列を python に公開する機能が利用できることを知っています -これは役立つかもしれません。

于 2008-08-26T15:58:08.880 に答える
6

コンパイルされたコードへの最終的な移行を計画する最良の方法は、基本的なデータ型を受け入れて返す機能的なスタイル(ステートレスで副作用のない) の単純な関数のモジュールとして、パフォーマンスに敏感な部分を記述することです。

これにより、Python プロトタイプ コードから最終的にコンパイルされたコードへの 1 対 1 のマッピングが提供され、ctypesを簡単に使用できるようになり、一連の頭痛の種を回避できます。

ピーク フィッティングでは、ほぼ確実に配列を使用する必要があります。これは少し複雑になりますが、ctypes を使用すると非常に実行可能です。

より複雑なデータ構造を使用したり、渡された引数を変更したりしたい場合は、SWIGまたはPython の標準 C 拡張インターフェイスを使用すると、必要なことを実行できますが、多少の手間がかかります。

あなたがやっていることについては、NumPyをチェックアウトすることもできます。これは、 C にプッシュしたい作業の一部を実行するだけでなく、Python と C の間でデータをやり取りする際の追加のヘルプを提供します。

于 2008-08-20T01:45:05.390 に答える
4

f2py (の一部numpy) は、C/Fortran の数値計算コードをラップするための SWIG および boost.python のより単純な代替手段です。

于 2008-09-29T22:30:59.973 に答える
1

私の経験では、Python コードから C コードを呼び出す簡単な方法が 2 つあります。他のアプローチもありますが、それらはすべて煩わしく、冗長です。

最初の最も簡単な方法は、一連の C コードを個別の共有ライブラリとしてコンパイルし、ctypes を使用してそのライブラリ内の関数を呼び出すことです。残念ながら、基本的なデータ型以外のものを渡すことは簡単ではありません。

2 番目に簡単な方法は、C で Python モジュールを作成し、そのモジュールで関数を呼び出すことです。これらの C 関数には、面倒なことをせずに何でも渡すことができます。また、 https ://docs.python.org/extending/extending.html#calling-python-functions-from-c で説明されているように、これらの C 関数から Python 関数またはメソッドを簡単に呼び出すことができます。

私は SWIG についての十分な経験がなく、賢明な解説を提供することができません。また、カスタム Python オブジェクトを ctypes を介して C 関数に渡したり、C で新しい Python クラスを定義したりすることは可能ですが、これらは面倒で冗長なので、上記の 2 つの方法のいずれかを使用することをお勧めします。

于 2008-08-19T13:52:23.033 に答える
0

Python は、関数、ファンクター、オブジェクトを関数やメソッドに渡すことを許可する点でかなり寛大ですが、C や Fortran などには同じことが当てはまらないのではないかと思います。

C では、関数の引数として関数を渡すことはできませんが、関数と同じくらい良い関数ポインターを渡すことはできます。

C と Python のコードを統合しようとしているときに、それがどれほど役立つかはわかりませんが、1 つの誤解を解消したかっただけです。

于 2008-09-29T22:52:19.580 に答える
0

上記のツールに加えて、Pyrex (Python 拡張モジュールの作成用) またはPsyco (Python の JIT コンパイラーとして) の使用をお勧めします。

于 2009-05-16T15:08:53.677 に答える