12

P / Invokeを学習する過程で、私はこの前の質問をしました:

ポインタが関係しているときにP/Invokeする方法

ただし、マネージC ++でラッパーを作成するよりも、C#でP/Invokeを使用することの意味をよく理解していません。C#でP / Invokeを使用して同じDLLを作成すると、埋め込みリソースでDLLImportを使用できるため、インターフェイスがよりクリーンになりますが、マーシャリングを自分で行うネイティブDLLのマネージC ++ラッパーの方がパフォーマンスが向上しますか?

4

2 に答える 2

14

C++ ラッパーの方が高速である必要があります。次のMSDN ページをご覧ください。

C++ Interop は可能な限り高速なデータ マーシャリングの方法を使用しますが、P/Invoke は最も堅牢な方法を使用します。これは、C++ 相互運用性 (C++ に典型的な方法) がデフォルトで最適なパフォーマンスを提供することを意味し、プログラマーはこの動作が安全または適切でない場合に対処する責任があります。

つまり、基本的に主な理由は、P/Invoke がピン留め、ブリッティング、エラー チェックを行うのに対して、C++ 相互運用機能はスタックにパラメーターをプッシュして関数を呼び出すだけだからです。

覚えておくべきもう 1 つのポイントは、C++ は 1 回の呼び出しで複数の API を呼び出すことができるということです。一方で、アドレスによって渡された P/Invoke EVERY パラメーターは、すべての呼び出しで固定および固定解除され、コピーおよびコピーバックされます。

于 2009-09-16T14:48:29.123 に答える
6

パフォーマンスが向上しますか?何をしているのか、どのようにしているのかによって異なります。一般的に言えば、パフォーマンスへの影響は、マネージド/アンマネージド トランジションを行うことで発生する可能性が高く、カットできるトランジションが多ければ多いほど効果的です。理想的には、アンマネージ コードへのインターフェイスは分厚く、おしゃべりにならないようにする必要があります。

数千のオブジェクトのコレクションを持つアンマネージ コードがあるとします。次のような API をマネージ コードに公開できます。

int GetFooCount();
IntPtr GetFoo(int n);
void ReleaseFoo(IntPtr p);

次のように C# で使用を開始するまでは、これで問題ありません。

int total = API.GetFooCount();
IntPtr[] objects = new IntPtr[total];
for (int i=0; i < total; i++) {
    objects[i] = GetFoo(i);
}
// and later:
foreach (IntPtr p in objects) { ReleaseFoo(p); }

合計 == 1000 の場合、4002 のマネージド/アンマネージド トランジションになります。代わりにこれがある場合:

int GetFooCount();
void GetFoos(IntPtr[] arr, int start, int count);
void ReleaseFoos(IntPtr arr, int start, int count);

次に、6 つのトランジションで同じ作業を行うことができます。どちらがより良いパフォーマンスを発揮すると思いますか?

もちろん、次の重要な質問は、「このパフォーマンスの向上は価値があるか?」ということです。最初に測定することを忘れないでください。

また、注意すべきことの 1 つは、マネージ C++ を使用しているときに、STL に奇妙なことが起こる可能性があるということです。たまたま STL を使用しているアンマネージ ライブラリ コードがあります。私の経験では、マネージ C++ で STL 型のいずれかに触れたことがあれば、それらすべてがマネージ実装になったということです。これの最終結果は、リストを繰り返しながら、低レベルのコードがマネージド/アンマネージド トランジションを行っていたことです。うわぁ。STL 型をマネージ C++ に公開しないことで、これを解決しました。

私たちの経験では、可能であれば、C#->マネージド C++ ラッパー->スタティック ライブラリに移動する方がはるかに優れています。

于 2009-09-16T14:53:31.767 に答える