Interop (C++) のパフォーマンスに関する考慮事項
このトピックでは、マネージまたはアンマネージ相互運用機能の遷移による実行時パフォーマンスへの影響を小さくするためのガイドラインを示します。
Visual C++ は、Visual Basic や C# (P/Invoke) など、他の .NET 言語がサポートしているのと同じ相互運用機構をサポートしていることに加え、Visual C++ 固有の相互運用機能 (C++ Interop) もサポートしています。パフォーマンスを重要視するアプリケーションでは、各相互運用手法におけるパフォーマンスへの影響を理解することが重要です。
使用する相互運用手法に関係なく、マネージ関数からアンマネージ関数、またはアンマネージ関数からマネージ関数を呼び出すたびに、サンクと呼ばれる特別な遷移シーケンスが必要となります。Visual C++ コンパイラは、これらのサンクを自動的に挿入します。ただし、これらの遷移を行うと累積的にパフォーマンスを低下させる可能性があることを考慮する必要があります。
遷移の削減
相互運用機能サンクによる負荷を回避または削減する方法として、マネージ遷移またはアンマネージ遷移を最小限にするために、関係するインターフェイスをリファクタリングする方法が挙げられます。マネージ境界またはアンマネージ境界を超えた頻繁な呼び出しを行う、使用頻度の高いインターフェイスを指定することで、大幅にパフォーマンスを向上させることができます。たとえば、短いループでアンマネージ関数を呼び出すマネージ関数はリファクタリングに適しています。このループ自体をアンマネージ側に移動したり、アンマネージ呼び出しに代わるマネージ呼び出しを作成したりする (おそらく、マネージ側のキューにデータを追加し、ループ後にそのデータを一括してアンマネージ API にマーシャリングする) と、遷移回数を大幅に削減できます。
P/Invoke とC++ Interop
Visual Basic や C# などの .NET 言語では、ネイティブ コンポーネントとの相互運用方法として P/Invoke が定義されています。P/Invoke は .NET Framework によってサポートされるため、Visual C++ でもサポートされていますが、さらに Visual C++ では独自の相互運用機能がサポートされています。この相互運用機能が C++ Interop です。P/Invoke はタイプセーフではないため、できるだけ C++ Interop を使用することをお勧めします。結果としてエラーは主に実行時に報告されますが、C++ Interop はパフォーマンス的にも P/Invoke より優れています。
どちらの手法を使用しても、マネージ関数がアンマネージ関数を呼び出す際には次の処理を実行する必要があります。
関数呼び出しの引数を CLR 型からネイティブ型にマーシャリングします。
マネージからアンマネージのサンクを実行します。
引数のネイティブ バージョンを使用してアンマネージ関数を呼び出します。
アンマネージからマネージのサンクを実行します。
戻り値の型およびすべての "out" 引数および "in,out" 引数をネイティブ型から CLR 型にマーシャリングします。
マネージまたはアンマネージのサンクは、相互運用機能が完全に機能するために必要ですが、必要となるデータのマーシャリングは、関係するデータ型、関数シグネチャ、およびデータの使用方法によって異なります。
C++ Interop が実行するデータのマーシャリングは、非常に簡単な形式です。マネージ境界またはアンマネージ境界を超えてパラメーターをビット単位で単にコピーするだけで、遷移は一切行われません。P/Invoke で遷移が行われないのは、すべてのパラメーターが単純な bittable 型である場合だけです。それ以外の場合、P/Invoke は非常に信頼性の高いステップを実行して、引数が "out" または "in,out" とマークされている場合、各マネージ パラメーターを適切なネイティブ型に変換します。
言い換えれば、C++ Interop はデータのマーシャリングに最も速い方法を使用するのに対し、P/Invoke は最も信頼性の高い方法を使用します。つまり、C++ Interop (C++ での典型的な方法) には既定で最適なパフォーマンスが提供されており、この動作が安全でなかったり、適切でなかったりする場合、それに対処するのはプログラマの役割であるということです。
したがって、C++ Interop では、データのマーシャリングを明示的に指定することが必要ですが、データの性質に応じて何が適切であるか、またデータをどのように使用するかをプログラマが自由に選択できるという利点があります。さらに、P/Invoke のデータ マーシャリングの動作は、カスタマイズ時にある程度の変更ができますが、C++ Interop では呼び出しベースでデータ マーシャリングをカスタマイズできます。P/Invoke では、このようなカスタマイズは実行できません。
C++ Interop の詳細については、「C++ Interop (暗黙の PInvoke) の使用」を参照してください。