この記事では、CPython 用の C++ 拡張モジュールを構築して双曲線正接を計算し、Python コードから呼び出します。 このルーチンは、C++ で同じルーチンを実装する場合の相対的なパフォーマンス向上を示すために、Python で最初に実装されます。
C++ (または C) で記述されたコード モジュールは、Python インタープリターの機能を拡張するために一般的に使用されます。 拡張モジュールには、主に次の 3 種類があります。
- アクセラレータ モジュール: 高速パフォーマンスを有効にします。 Python は解釈された言語であるため、パフォーマンスを向上させるために C++ でアクセラレータ モジュールを記述できます。
- ラッパー モジュール: 既存の C/C++ インターフェイスを Python コードに公開するか、Python から簡単に使用できる Python のような API を公開します。
-
低レベルのシステム アクセス モジュール:
CPython
ランタイム、オペレーティング システム、または基になるハードウェアの下位レベルの機能に到達するシステム アクセス モジュールを作成します。
この記事では、Python で C++ 拡張モジュールを使用できるようにする 2 つの方法を示します。
-
CPython
の説明に従って、標準の拡張機能を使用します。 - PyBind11 を使用します。これは、C++11 のシンプルさから推奨されます。 互換性を確保するには、Python の最新バージョンの 1 つを使用していることを確認します。
このチュートリアルの完成したサンプルは、 GitHub の python-samples-vs-cpp-extension で入手できます。
[前提条件]
Python 開発ワークロードがインストールされている Visual Studio 2017 以降。 ワークロードには、ネイティブ拡張機能に必要な C++ ワークロードとツールセットを追加する Python ネイティブ開発ツールが含まれています。
インストール オプションの詳細については、「 Visual Studio の Python サポートをインストールする」を参照してください。
注
データ サイエンスおよび分析アプリケーションワークロードをインストールすると、Python と Python ネイティブ開発ツールオプションが既定でインストールされます。
Python を個別にインストールする場合は、Python インストーラーの [詳細オプション] の下にある [デバッグ シンボルのダウンロード] を選択してください。 このオプションは、Python コードとネイティブ コードの間で混合モードデバッグを使用するために必要です。
Python アプリケーションを作成する
Python アプリケーションを作成するには、次の手順に従います。
File>New>Project を選択して、Visual Studio で新しい Python プロジェクトを作成します。
[ 新しいプロジェクトの作成 ] ダイアログで、 Python を検索します。 Python アプリケーション テンプレートを選択し、[次へ] を選択します。
プロジェクト名と場所を入力し、[作成] を選択します。
Visual Studio によって新しいプロジェクトが作成されます。 ソリューション エクスプローラーでプロジェクトが開き、コード エディターでプロジェクト ファイル (.py) が開きます。
.py ファイルに、次のコードを貼り付けます。 Python の編集機能の一部を体験するには、コードを手動で入力してみてください。
このコードでは、数学ライブラリを使用せずに双曲線正接を計算します。これは、後で Python ネイティブ拡張機能を使用して加速するものです。
ヒント
C++ で書き直す前に、純粋な Python でコードを記述します。 これにより、ネイティブ Python コードが正しいことを簡単に確認できます。
from random import random from time import perf_counter # Change the value of COUNT according to the speed of your computer. # The value should enable the benchmark to complete in approximately 2 seconds. COUNT = 500000 DATA = [(random() - 0.5) * 3 for _ in range(COUNT)] e = 2.7182818284590452353602874713527 def sinh(x): return (1 - (e ** (-2 * x))) / (2 * (e ** -x)) def cosh(x): return (1 + (e ** (-2 * x))) / (2 * (e ** -x)) def tanh(x): tanh_x = sinh(x) / cosh(x) return tanh_x def test(fn, name): start = perf_counter() result = fn(DATA) duration = perf_counter() - start print('{} took {:.3f} seconds\n\n'.format(name, duration)) for d in result: assert -1 <= d <= 1, " incorrect values" if __name__ == "__main__": print('Running benchmarks with COUNT = {}'.format(COUNT)) test(lambda d: [tanh(x) for x in d], '[tanh(x) for x in d] (Python implementation)')
[デバッグ>デバッグなしで開始] を選択するか、キーボード ショートカット Ctrl + F5 キーを押してプログラムを実行します。
コマンド ウィンドウが開き、プログラムの出力が表示されます。
出力で、ベンチマーク プロセスで報告された時間に注目してください。
このチュートリアルでは、ベンチマーク プロセスには約 2 秒かかります。
必要に応じて、コード内の
COUNT
変数の値を調整して、ベンチマークがコンピューター上で約 2 秒で完了できるようにします。プログラムをもう一度実行し、変更された
COUNT
値が約 2 秒でベンチマークを生成するかどうかを確認します。
ヒント
ベンチマークを実行する場合は、常に Debug>Start without Debugging オプションを 使用します。 このメソッドは、Visual Studio デバッガー内でコードを実行するときに発生する可能性があるオーバーヘッドを回避するのに役立ちます。
コア C++ プロジェクトを作成する
次の手順に従って、 superfastcode と superfastcode2 という 2 つの同一の C++ プロジェクトを作成します。 後で、各プロジェクトで異なるアプローチを使用して、C++ コードを Python に公開します。
ソリューション エクスプローラーで、ソリューション名を右クリックし、[追加>新しいプロジェクト] を選択します。
Visual Studio ソリューションには、Python と C++ の両方のプロジェクトを含めることができます。これは、Python 開発に Visual Studio を使用する利点の 1 つです。
[新しいプロジェクトの追加] ダイアログで、[言語] フィルターを [C++] に設定し、[検索] ボックスに「空」と入力します。
プロジェクト テンプレートの結果の一覧で、[ 空のプロジェクト] を選択し、[ 次へ] を選択します。
[ 新しいプロジェクトの構成 ] ダイアログで、[ プロジェクト名] を入力します。
- 最初のプロジェクトの場合は、 superfastcode という名前を入力します。
- 2 番目のプロジェクトの場合は、 superfastcode2 という名前を入力します。
を選択してを作成します。
必ずこれらの手順を繰り返し、2 つのプロジェクトを作成してください。
ヒント
Visual Studio に Python ネイティブ開発ツールがインストールされている場合は、別の方法を使用できます。 この記事で説明する手順の多くを事前に完了している Python 拡張機能モジュール テンプレートから始めることができます。
この記事のチュートリアルでは、空のプロジェクトから始めて、拡張機能モジュールを段階的にビルドする方法を示すのに役立ちます。 プロセスを理解したら、代替テンプレートを使用して、独自の拡張機能を記述するときに時間を節約できます。
C++ ファイルをプロジェクトに追加する
次に、各プロジェクトに C++ ファイルを追加します。
ソリューション エクスプローラーでプロジェクトを展開し、[ソース ファイル] ノードを右クリックし、[追加>新しい項目] を選択します。
ファイル テンプレートの一覧で、 C++ ファイル (.cpp) を選択します。
ファイルの 名前 を module.cppとして入力し、[ 追加] を選択します。
Von Bedeutung
ファイル名に .cpp 拡張子が含まれていることを確認します。 Visual Studio は、C++ プロジェクトのプロパティ ページの表示を有効にするために 、.cpp 拡張子を持つファイルを探します。
ツール バーの [ 構成 ] ドロップダウン メニューを展開し、ターゲット構成の種類を選択します。
- 64 ビット Python ランタイムの場合は、 x64 構成をアクティブにします。
- 32 ビット Python ランタイムの場合は、 Win32 構成をアクティブにします。
両方のプロジェクトでこれらの手順を繰り返してください。
プロジェクトのプロパティを構成する
新しい C++ ファイルにコードを追加する前に、各 C++ モジュール プロジェクトのプロパティを構成し、構成をテストしてすべてが動作していることを確認します。
各モジュールの デバッグ ビルド構成と リリース ビルド構成の両方のプロジェクト プロパティを設定する必要があります。
ソリューション エクスプローラーで、C++ モジュール プロジェクト (superfastcode または superfastcode2) を右クリックし、[プロパティ] を選択します。
モジュールの デバッグ ビルドのプロパティを構成し、 リリース ビルドと同じプロパティを構成します。
プロジェクトの [プロパティ ページ] ダイアログの上部で、次のファイル構成オプションを構成します。
[構成] で、[デバッグ] または [リリース] を選択します。 (これらのオプションには 、Active プレフィックスが付いている場合があります)。
プラットフォームの場合は、前の手順で選択した内容に応じて、アクティブ (x64) またはアクティブ (Win32) を選択します。
注
独自のプロジェクトを作成するときは、特定のシナリオの要件に従って、 デバッグ 構成と リリース 構成を個別に構成する必要があります。 この演習では、CPython のリリース ビルドを使用するように構成を設定します。 この構成により、アサーションを含む C++ ランタイムのデバッグ機能の一部が無効になります。 CPython デバッグ バイナリ (python_d.exe) を使用するには、異なる設定が必要です。
次の表に示すように、他のプロジェクト プロパティを設定します。
プロパティ値を変更するには、プロパティ フィールドに値を入力します。 一部のフィールドでは、現在の値を選択して選択肢のドロップダウン メニューを展開したり、ダイアログを開いて値を定義したりできます。
タブの値を更新した後、別のタブに切り替える前に [適用 ] を選択します。このアクションは、変更を確実に維持するのに役立ちます。
タブとセクション プロパティ 価値 構成プロパティ>全般 ターゲット名 from...import
などのステートメントで Python から参照するモジュールの名前指定します。 Python のモジュールを定義するときは、C++ コードでこれと同じ名前を使用します。 プロジェクトの名前をモジュール名として使用するには、既定値の $<ProjectName> のままにします。python_d.exe
の場合は、名前の末尾に_d
を追加します。[構成の種類] ダイナミック ライブラリ (.dll) 構成プロパティ>アドバンスド ターゲット ファイル拡張子 .pyd (Python 拡張機能モジュール) C/C++>全般 追加のインクルード ディレクトリ インストールに適した Python インクルード フォルダーを追加します (例 : c:\Python36\include)。 C/C++>プリプロセッサ プリプロセッサ定義 存在する場合は、 _DEBUG 値を NDEBUG に変更して、CPython の非デバッグ バージョンと一致させます。 python_d.exeを使用する場合、この値は変更しません。 C/C++>コード生成 ランタイム ライブラリ CPython のリリース (非デバッグ) バージョンと一致するマルチスレッド DLL (/MD)。 python_d.exeを使用する場合は、この値をマルチスレッド デバッグ DLL (/MDd) のままにします。 基本的なランタイム チェック デフォルト リンカー>全般 その他のライブラリ ディレクトリ インストールに応じて、.lib ファイルを含む Python libs フォルダーを追加します (例: c:\Python36\libs)。 .pyファイルを含む Lib フォルダーではなく、.libファイルを含む libs フォルダーを必ずポイントしてください。 Von Bedeutung
[C/C++] タブがプロジェクト プロパティのオプションとして表示されない場合、Visual Studio で C/C++ ソース ファイルとして識別されるコード ファイルはプロジェクトに含まれません。 その状態は、.cや.cppといったファイル拡張子を持たないソースファイルを作成した場合に発生する可能性があります。
C++ ファイルの作成時に、module.cppの代わりに module.coo を誤って入力した場合、Visual Studio によってファイルが作成されますが、ファイルの種類は C/C+ コンパイラに設定されません。 このファイルの種類は、プロジェクトのプロパティ ダイアログの [C/C++ プロパティ] タブの存在をアクティブ化するために必要です。 コード ファイルの名前を .cpp ファイル拡張子 で変更しても、誤った識別は残ります。
コード ファイルの種類を正しく設定するには、 ソリューション エクスプローラーでコード ファイルを右クリックし、[ プロパティ] を選択します。 [項目の種類] で、[C/C++ コンパイラ] を選択します。
すべてのプロパティを更新したら、[ OK] を選択します。
他のビルド構成の手順を繰り返します。
現在の構成をテストします。 両方の C++ プロジェクトの デバッグ ビルドと リリース ビルドの両方について、次の手順を繰り返します。
コードとテスト構成を追加する
これで、C++ ファイルにコードを追加し、 リリース ビルドをテストする準備ができました。
superfastcode C++ プロジェクトの場合は、コード エディターで module.cpp ファイルを開きます。
module.cpp ファイルに、次のコードを貼り付けます。
#include <Windows.h> #include <cmath> const double e = 2.7182818284590452353602874713527; double sinh_impl(double x) { return (1 - pow(e, (-2 * x))) / (2 * pow(e, -x)); } double cosh_impl(double x) { return (1 + pow(e, (-2 * x))) / (2 * pow(e, -x)); } double tanh_impl(double x) { return sinh_impl(x) / cosh_impl(x); }
変更を保存します。
C++ プロジェクトの リリース 構成をビルドして、コードが正しいことを確認します。
手順を繰り返して 、superfastcode2 プロジェクトの C++ ファイルにコードを追加し、 リリース ビルドをテストします。
C++ プロジェクトを Python 拡張機能に変換する
C++ DLL を Python の拡張機能にするには、最初にエクスポートされたメソッドを変更して Python 型と対話します。 次に、モジュールのメソッドの定義と共に、モジュールをエクスポートする関数を追加します。
次のセクションでは、CPython 拡張機能と PyBind11 を使用して拡張機能を作成する方法について説明します。 superfasctcode プロジェクトは CPython 拡張機能を使用し、superfasctcode2 プロジェクトは PyBind11 を実装します。
CPython 拡張機能を使用する
このセクションで説明するコードの詳細については、「 Python/C API リファレンス マニュアル(特に モジュール オブジェクト) 」ページを参照してください。 参照コンテンツを確認するときは、右上のドロップダウン リストで Python のバージョンを選択してください。
superfastcode C++ プロジェクトの場合は、コード エディターで module.cpp ファイルを開きます。
python.h ヘッダー ファイルを含めるために、module.cpp ファイルの先頭にステートメントを追加します。
#include <Python.h>
python 型 (つまり、
tanh_impl
) を受け入れて返すように、PyObject*
メソッド コードを置き換えます。PyObject* tanh_impl(PyObject* /* unused module reference */, PyObject* o) { double x = PyFloat_AsDouble(o); double tanh_x = sinh_impl(x) / cosh_impl(x); return PyFloat_FromDouble(tanh_x); }
ファイルの最後に、C++
tanh_impl
関数を Python に表示する方法を定義する構造体を追加します。static PyMethodDef superfastcode_methods[] = { // The first property is the name exposed to Python, fast_tanh // The second is the C++ function with the implementation // METH_O means it takes a single PyObject argument { "fast_tanh", (PyCFunction)tanh_impl, METH_O, nullptr }, // Terminate the array with an object containing nulls { nullptr, nullptr, 0, nullptr } };
python コードでモジュールを参照する方法を定義する別の構造を追加します。具体的には、
from...import
ステートメントを使用する場合です。このコードでインポートする名前は、プロジェクト プロパティの [構成プロパティ] の値と一致する必要があります>General>Target Name。
次の例では、
"superfastcode"
名は、from superfastcode import fast_tanh
がfast_tanh
内で定義されているため、Python でsuperfastcode_methods
ステートメントを使用できることを意味します。 module.cppなど、C++ プロジェクトの内部にあるファイル名は重要ではありません。static PyModuleDef superfastcode_module = { PyModuleDef_HEAD_INIT, "superfastcode", // Module name to use with Python import statements "Provides some functions, but faster", // Module description 0, superfastcode_methods // Structure that defines the methods of the module };
Python がモジュールを読み込むときに呼び出すメソッドを追加します。 メソッド名は
PyInit_<module-name>
する必要があります。 <module-name> は C++ プロジェクトの Configuration Properties>General>Target Name プロパティと正確に一致します。 つまり、メソッド名は、プロジェクトによってビルドされた .pyd ファイルのファイル名と一致します。PyMODINIT_FUNC PyInit_superfastcode() { return PyModule_Create(&superfastcode_module); }
C++ プロジェクトをビルドし、コードを確認します。 エラーが発生した場合は、「 コンパイル エラーのトラブルシューティング」 セクションを参照してください。
PyBind11 を使用する
superfastcode プロジェクトの前のセクションの手順を完了すると、C++ CPython 拡張機能のモジュール構造を作成するための定型コードが演習に必要な場合があります。 この演習では、PyBind11 によってコーディング プロセスが簡略化されることを確認します。 同じ結果を得るために C++ ヘッダー ファイル内のマクロを使用しますが、コードははるかに少なくなります。 ただし、Visual Studio で PyBind11 ライブラリとインクルード ファイルを検索できるようにするには、追加の手順が必要です。 このセクションのコードの詳細については、「 PyBind11 の基本」を参照してください。
PyBind11 のインストール
最初の手順では、プロジェクト構成に PyBind11 をインストールします。 この演習では、 開発者 PowerShell ウィンドウを使用します。
[ツール>コマンド ライン>Developer PowerShell] ウィンドウを開きます。
開発者 PowerShell ウィンドウで、pip コマンド
pip install pybind11
またはpy -m pip install pybind11
を使用して PyBind11 をインストールします。Visual Studio では、PyBind11 とその依存パッケージがインストールされます。
PyBind11 パスをプロジェクトに追加する
PyBind11 をインストールしたら、プロジェクトの 追加インクルード ディレクトリ プロパティに PyBind11 パスを追加する必要があります。
Developer PowerShell ウィンドウで、コマンド
python -m pybind11 --includes
またはpy -m pybind11 --includes
を実行します。この操作により、プロジェクトのプロパティに追加する必要がある PyBind11 パスの一覧が出力されます。
ウィンドウ内のパスの一覧を強調表示し、ウィンドウ ツール バーの [コピー ] (ダブル ページ) を選択します。
連結されたパスの一覧がクリップボードに追加されます。
ソリューション エクスプローラーでsuperfastcode2 プロジェクトを右クリックし、[プロパティ] を選択します。
[ プロパティ ページ ] ダイアログの上部にある [構成 ] フィールドで、[ リリース] を選択します。 (このオプションには 、Active プレフィックスが付いている場合があります)。
ダイアログの [C/C++>General ] タブで、[ 追加のインクルード ディレクトリ ] プロパティのドロップダウン メニューを展開し、[編集] を選択 します。
ポップアップ ダイアログで、コピーしたパスの一覧を追加します。
Developer PowerShell ウィンドウからコピーした連結リスト内の各パスに対して、次の手順を繰り返します。
ポップアップ ダイアログのツールバーで[新しいライン] (プラス記号付きフォルダー) を選択します。
Visual Studio では、パスの一覧の上部に空の行が追加され、挿入カーソルが先頭に配置されます。
PyBind11 パスを空の行に貼り付けます。
その他のオプション (...) を選択し、ポップアップ ファイル エクスプローラー ダイアログを使用してパスの場所を参照することもできます。
Von Bedeutung
- パスに
-I
プレフィックスが含まれている場合は、パスからプレフィックスを削除します。 - Visual Studio でパスを認識するには、パスを別の行に配置する必要があります。
新しいパスを追加すると、Visual Studio の [評価された値 ] フィールドに確認済みのパスが表示されます。
- パスに
[ OK] を 選択してポップアップ ダイアログを終了します。
[ プロパティ ページ ] ダイアログの上部で、[ 追加のインクルード ディレクトリ ] プロパティの値をポイントし、PyBind11 パスが存在することを確認します。
[OK] を選択して、プロパティの変更内容を適用します。
module.cpp ファイルを更新する
最後の手順では、PyBind11 ヘッダー ファイルとマクロ コードをプロジェクト C++ ファイルに追加します。
superfastcode2 C++ プロジェクトの場合は、コード エディターで module.cpp ファイルを開きます。
pybind11.h ヘッダー ファイルを含めるために、module.cpp ファイルの先頭にステートメントを追加します。
#include <pybind11/pybind11.h>
module.cpp ファイルの最後に、
PYBIND11_MODULE
マクロのコードを追加して、C++ 関数へのエントリ ポイントを定義します。namespace py = pybind11; PYBIND11_MODULE(superfastcode2, m) { m.def("fast_tanh2", &tanh_impl, R"pbdoc( Compute a hyperbolic tangent of a single argument expressed in radians. )pbdoc"); #ifdef VERSION_INFO m.attr("__version__") = VERSION_INFO; #else m.attr("__version__") = "dev"; #endif }
C++ プロジェクトをビルドし、コードを確認します。 エラーが発生した場合は、次のセクション「 コンパイル エラーのトラブルシューティング」を参照してください。
コンパイル エラーのトラブルシューティング
C++ モジュールのビルドが失敗する可能性がある問題については、次のセクションを確認してください。
エラー: ヘッダー ファイルが見つかりません
Visual Studio は E1696: ソースファイル "Python.h" を開くことができません または C1083: インクルードファイル "Python.h" を開くことができません。そんなファイルまたはディレクトリはありません というエラーメッセージを返します。
このエラーは、コンパイラがプロジェクトに必要なヘッダー (.h) ファイルを見つけることができないことを示します。
superfastcode プロジェクトの場合は、C/C++>General>Additional Include Directories プロジェクト プロパティに、Python インストールのインクルード フォルダーへのパスが含まれていることを確認します。 「プロジェクトのプロパティを構成する」の手順を確認します。
superfastcode2 プロジェクトの場合は、同じプロジェクト プロパティに PyBind11 インストールのインクルード フォルダーへのパスが含まれていることを確認します。 「プロジェクトに PyBind パスを追加する手順を確認します。」
Python のインストール構成情報へのアクセスの詳細については、 Python のドキュメントを参照してください。
エラー: Python ライブラリが見つからない
Visual Studio は、コンパイラがプロジェクトに必要なライブラリ (DLL) ファイルを見つけることができないことを示すエラーを返します。
- C++ プロジェクト (superfastcode または superfastcode2) の場合は、Linker>> プロパティに Python インストール用の libs フォルダーへのパスが含まれていることを確認します。 「プロジェクトのプロパティを構成する」の手順を確認します。
Python のインストール構成情報へのアクセスの詳細については、 Python のドキュメントを参照してください。
ターゲット アーキテクチャに関連するリンカー エラー
Visual Studio は、x64 や Win32 など、プロジェクトのターゲット アーキテクチャ構成に関連するリンカー エラーを報告します。
- C++ プロジェクト (superfastcode または superfastcode2) の場合は、Python のインストールに合わせてターゲット構成を変更します。 たとえば、C++ プロジェクトのターゲット構成が Win32 で、Python のインストールが 64 ビットである場合は、C++ プロジェクトターゲットの構成を x64 に変更します。
コードをテストし、結果を比較する
これで、DLL が Python 拡張機能として構造化されたので、Python プロジェクトから DLL を参照し、モジュールをインポートして、そのメソッドを使用できます。
DLL を Python で使用できるようにする
DLL を Python で使用できるようにするには、いくつかの方法があります。 考慮すべき 2 つのオプションを次に示します。
Python プロジェクトと C++ プロジェクトが同じソリューション内にある場合は、次の方法を使用できます。
ソリューション エクスプローラーで、Python プロジェクトの [参照] ノードを右クリックし、[参照の追加] を選択します。
C++ プロジェクトではなく、Python プロジェクトに対してこのアクションを実行してください。
[ 参照の追加 ] ダイアログで、[ プロジェクト ] タブを展開します。
superfastcode プロジェクトと superfastcode2 プロジェクトの両方のチェック ボックスをオンにし、[OK] を選択します。
別の方法として、Python 環境に C++ 拡張機能モジュールをインストールします。 このメソッドを使用すると、他の Python プロジェクトでモジュールを使用できるようになります。 詳細については、 setuptools プロジェクトのドキュメントを参照してください。
Python 環境に C++ 拡張機能モジュールをインストールするには、次の手順を実行します。
ソリューション エクスプローラーで、C++ プロジェクトを右クリックし、[追加>新しい項目] を選択します。
ファイル テンプレートの一覧で、 C++ ファイル (.cpp) を選択します。
ファイルの 名前 を setup.py として入力し、[ 追加] を選択します。
ファイル名には、必ず Python (.py) 拡張子を付けて入力してください。 Visual Studio は、C++ ファイル テンプレートを使用しているにもかかわらず、ファイルを Python コードとして認識します。
Visual Studio がコード エディターで新しいファイルを開きます。
次のコードを新しいファイルに貼り付けます。 拡張メソッドに対応するコード バージョンを選択します。
CPython 拡張機能 (superfastcode プロジェクト):
from setuptools import setup, Extension sfc_module = Extension('superfastcode', sources = ['module.cpp']) setup( name='superfastcode', version='1.0', description='Python Package with superfastcode C++ extension', ext_modules=[sfc_module] )
PyBind11 (superfastcode2 プロジェクト):
from setuptools import setup, Extension import pybind11 cpp_args = ['-std=c++11', '-stdlib=libc++', '-mmacosx-version-min=10.7'] sfc_module = Extension( 'superfastcode2', sources=['module.cpp'], include_dirs=[pybind11.get_include()], language='c++', extra_compile_args=cpp_args, ) setup( name='superfastcode2', version='1.0', description='Python package with superfastcode2 C++ extension (PyBind11)', ext_modules=[sfc_module], )
C++ プロジェクトで pyproject.toml という名前の 2 つ目のファイルを作成し、次のコードを貼り付けます。
[build-system] requires = ["setuptools", "wheel", "pybind11"] build-backend = "setuptools.build_meta"
TOML (.toml) ファイルは、構成ファイルに Tom の明らかな最小言語形式を使用します。
拡張機能をビルドするには、コード ウィンドウ タブで pyproject.toml ファイル名を右クリックし、[ 完全パスのコピー] を選択します。
使用する前に、パスから pyproject.toml の名を削除します。
ソリューション エクスプローラーで、ソリューションの [Python 環境] ノードを展開します。
アクティブな Python 環境 (太字で表示) を右クリックし、[ Python パッケージの管理] を選択します。
[ Python 環境 ] ウィンドウが開きます。
必要なパッケージが既にインストールされている場合は、このウィンドウに一覧表示されます。
- 続行する前に、パッケージ名の横にある X を選択してアンインストールします。
[Python 環境] ウィンドウの検索ボックスにコピーしたパスを貼り付け、パスの末尾から pyproject.toml ファイル名を削除します。
Enter キーを 押 して、コピーしたパスの場所からモジュールをインストールします。
ヒント
アクセス許可エラーが原因でインストールが失敗した場合は、コマンドの末尾に
--user
引数を追加して、もう一度インストールを試してください。
Python から DLL を呼び出す
前のセクションで説明したように、DLL を Python で使用できるようにするには、Python から superfastcode.fast_tanh
関数と superfastcode2.fast_tanh2
関数を呼び出す準備が整いました。 その後、関数のパフォーマンスを Python の実装と比較できます。
Python から拡張モジュール DLL を呼び出すには、次の手順に従います。
コード エディターで Python プロジェクトの .py ファイルを開きます。
ファイルの最後に、DLL からエクスポートされたメソッドを呼び出して出力を表示する次のコードを追加します。
from superfastcode import fast_tanh test(lambda d: [fast_tanh(x) for x in d], '[fast_tanh(x) for x in d] (CPython C++ extension)') from superfastcode2 import fast_tanh2 test(lambda d: [fast_tanh2(x) for x in d], '[fast_tanh2(x) for x in d] (PyBind11 C++ extension)')
[デバッグ>デバッグなしで開始] を選択するか、キーボード ショートカット Ctrl+F5 を使用して Python プログラムを実行します。
注
[ デバッグなしで開始] コマンドを使用できない場合は、 ソリューション エクスプローラーで Python プロジェクトを右クリックし、[ スタートアップ プロジェクトとして設定] を選択します。
プログラムが実行されると、C++ ルーチンの実行速度が Python 実装の約 5 ~ 20 倍速くなります。
一般的なプログラム出力の例を次に示します。
Running benchmarks with COUNT = 500000 [tanh(x) for x in d] (Python implementation) took 0.758 seconds [fast_tanh(x) for x in d] (CPython C++ extension) took 0.076 seconds [fast_tanh2(x) for x in d] (PyBind11 C++ extension) took 0.204 seconds
時間差がより顕著になるように、
COUNT
変数を大きくしてみてください。C++ モジュールの デバッグ ビルドも 、デバッグ ビルドの最適化が少なく、さまざまなエラー チェックが含まれているため、リリース ビルドよりも実行速度が遅くなります。 比較のためにビルド構成を切り替えてみますが、リリース構成用に前に設定したプロパティを必ず更新してください。
プロセスの速度とオーバーヘッドに対処する
出力では、PyBind11 拡張機能は CPython 拡張機能ほど高速ではありませんが、純粋な Python 実装よりも高速である必要があります。 この違いの主な理由は、 METH_O フラグを使用するためです。 このフラグは、複数のパラメーター、パラメーター名、またはキーワード引数をサポートしていません。 PyBind11 では、呼び出し元により Python に似たインターフェイスを提供するために、少し複雑なコードが生成されます。 テスト コードは関数を 500,000 回呼び出すので、結果によってオーバーヘッドが大幅に増幅される可能性があります。
for
ループをネイティブ Python コードに移動することで、オーバーヘッドをさらに減らすことができます。 この方法では、反復子プロトコル (またはpy::iterable
の PyBind11 型) を使用して各要素を処理します。 Python と C++ の間で繰り返し遷移を削除することは、シーケンスの処理にかかる時間を短縮する効果的な方法です。
インポート エラーのトラブルシューティング
モジュールをインポートしようとしたときに ImportError
メッセージが表示される場合は、次のいずれかの方法で解決できます。
プロジェクト参照を使用してビルドする場合は、C++ プロジェクトのプロパティが、Python プロジェクト用にアクティブ化された Python 環境と一致していることを確認します。 Include (.h) ファイルと Library (DLL) ファイルで同じフォルダーの場所が使用されていることを確認します。
出力ファイルの名前が正しいことを確認します ( superfastcode.pyd など)。 名前または拡張子が正しくないと、必要なファイルがインポートできなくなります。
setup.py ファイルを使用してモジュールをインストールする場合は、Python プロジェクト用にアクティブ化された Python 環境で
pip
コマンドを実行してください。 ソリューション エクスプローラーでプロジェクトのアクティブな Python 環境を展開すると、スーパーファストコードなどの C++ プロジェクトのエントリが表示されます。
C++ コードのデバッグ
Visual Studio では、Python と C++ コードの一緒のデバッグがサポートされています。 次の手順では 、superfastcode C++ プロジェクトのデバッグ プロセスを示しますが、 superfastcode2 プロジェクトのプロセスは同じです。
ソリューション エクスプローラーで、Python プロジェクトを右クリックし、[プロパティ] を選択します。
[プロパティ] ウィンドウで、[デバッグ] タブを選択し、[デバッグ>ネイティブ コードデバッグオプションを有効にする] を選択します。
ヒント
ネイティブ コードのデバッグを有効にすると、プログラムが終了した直後に Python 出力ウィンドウが閉じられ、一時停止せずに [キーを押して続行する ]プロンプトが表示されることがあります。 ネイティブ コードのデバッグを有効にした後に一時停止とプロンプトを強制するには、[
-i
の [実行>Interpreter 引数] フィールドに引数を追加します。この引数は、コードの実行後に Python インタープリターを対話型モードにします。 プログラムは、Ctrl +Z+Enter を押してウィンドウを閉じるのを待っています。 別の方法として、Python プログラムの最後にimport os
ステートメントとos.system("pause")
ステートメントを追加します。 このコードは、元の一時停止プロンプトを複製します。[ファイル>保存 (または Ctrl+) を選択して、プロパティの変更を保存します。
Visual Studio ツール バーで、[ ビルド 構成] を [デバッグ] に設定します。
コードは通常、デバッガーでの実行に時間がかかるため、Python プロジェクト
COUNT
.py ファイルの変数を既定値の約 5 倍小さい値に変更できます。 たとえば、 500000 から 100000 に変更します。C++ コードで、
tanh_impl
メソッドの最初の行にブレークポイントを設定します。[デバッグ]>[デバッグの開始] を選択するか、キーボード ショートカット F5 を使用してデバッガーを起動します。
ブレークポイント コードが呼び出されると、デバッガーは停止します。 ブレークポイントにヒットしない場合は、構成が [デバッグ ] に設定されていること、およびプロジェクトを保存したことを確認します。これはデバッガーの起動時に自動的に行われません。
ブレークポイントでは、C++ コードをステップ実行したり、変数を調べたりすることができます。 これらの機能の詳細については、「 Python と C++ を一緒にデバッグする」を参照してください。
代替アプローチ
次の表に示すように、Python 拡張機能はさまざまな方法で作成できます。 この記事では、最初の 2 行 ( CPython
と PyBind11
) について説明します。
方法 | ビンテージ | 代表的なユーザー |
---|---|---|
用の C/C++ 拡張モジュール CPython |
1991 | 標準ライブラリ |
PyBind11 (C++ に推奨) | 2015 | |
Cython (C に推奨) | 2007 | gevent、 kivy |
HPy | 2019 | |
mypyc | 2017 | |
ctypes | 2003 | oscrypto |
cffi | 2013 | cryptography, pypy |
SWIG | 1996 | crfsuite |
Boost.Python | 2002 | |
cppyy | 2017 |