31

私のチームは、大規模なシミュレーション アプリケーションの COM API を扱っています。ほとんどのシミュレーション ファイルは数百メガバイトに達し、開くと完全にメモリに読み込まれるように見えます。

私たちが実行する主なタスクは、ファイルのオブジェクト モデル内のすべての要素を繰り返し処理し、各要素に対して「何か」を実行することです。

最近、コード ベースを .NET 2 から VS 2010 の .NET 4 に移動したところ、反復速度が約 40 倍 (約 10 秒から約 8 分に) 低下しました。これを可能な限り最小のコード例 (10 行程度) に減らしました。これをVS 2005でコンパイルして実行し、VS 2010でプロジェクトを開いてコンパイルし、フレームワークを2のままにしました(メーカーが提供するCOM相互運用アセンブリを使用しています)。

2005 年にはテスト アプリは 10 秒で完了し、2010 年には 8 分かかりました。

何が原因でしょうか?

アップデート

コードは次と同等です。

var server = new Server();
var elements = server.Elements;
var elementCount = elements.Count;

for(int i = 0; i < elementsCount; ++i)
{
    var element = elements[i];
}

このコードは、VS 2005 よりも VS 2010 で実行するのに 40 倍の時間がかかります。

更新 2

あるケースで他のケースよりも操作が大幅に遅くなる唯一の理由は、異なるバージョンでは COM を介してデータが異なる方法で転送されるためであると私は合理化しました。

両方のケースのバインド ログを記録したところ、これが見つかりました。高速バージョンでは、CustomMarshalers のネイティブ イメージが見つかりません(これらは FUSLOGVW によってキャプチャされたバインディング ログです)。

mscorlib

mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.HTM

速い

LOG: Start binding of native image mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.
LOG: Start validating native image mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.
WRN: Native image does not satisfy request. Looking for next native image.
WRN: No matching native image found.

遅い

LOG: Start binding of native image mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.
LOG: Start validating native image mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.
LOG: Bind to native image succeeded.

カスタムマーシャラー

CustomMarshalers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

速い

LOG: Start binding of native image CustomMarshalers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.
LOG: Start validating native image CustomMarshalers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.
WRN: Native image does not satisfy request. Looking for next native image.
WRN: No matching native image found.

遅い

LOG: Start binding of native image CustomMarshalers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.
LOG: Start validating native image CustomMarshalers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.
LOG: Start validating all the dependencies.
LOG: [Level 1]Start validating native image dependency mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.
LOG: Dependency evaluation succeeded.
LOG: [Level 1]Start validating IL dependency Microsoft.VisualC, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.
LOG: Dependency evaluation succeeded.
LOG: Validation of dependencies succeeded.
LOG: Start loading all the dependencies into load context.
LOG: Loading of dependencies succeeded.
LOG: Bind to native image succeeded.
Native image has correct version information.
Attempting to use native image C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\CustomMarshalers\3e6deccf191ab943d3a0812a38ab5c97\CustomMarshalers.ni.dll.
Native image successfully used.

したがって、ネイティブ イメージを使用しない場合、パフォーマンスが大幅に向上するようです。

このバインドがある場合には失敗し、別の場合には成功するのはなぜですか? また、アプリケーションがネイティブ イメージを使用しないようにするにはどうすればよいでしょうか?

更新 3

奇妙さは続く。このコードを VS 2010 で R# テスト ランナーまたは組み込みの Visual Studio テスト ランナーを使用したテスト メソッドで実行すると、高速で実行されます。

このコードをアセンブリにラップしてから動的にロードしようとしましたが、違いはありません。

4

2 に答える 2

6

ちょっとロングショットでした。お役に立てて嬉しいです。

MTAとSTA(スレッドモデル)を一致させることは、COMオブジェクトに対して多数の個別の呼び出しを行う場合に非常に重要です。メソッドの先頭にある[STAThread]ディレクティブは、そのメソッドのすべての呼び出しに対してモデルをスレッド化するための1つの方法です。

スレッド全体で機能するように見えThread.SetApartmentState(ApartmentState.STA)ますが、スレッドプールスレッドでは機能しないようです。

于 2012-10-10T13:29:39.177 に答える
2

「...STAアプリケーションのスレッドでも...」と言うとき、それは実際には正しくありません。スレッドは、COMオブジェクトにアクセスする前にアパートメントの状態を設定することを選択できますが、.NETでは、何もしないと、それらのスレッドは暗黙的にMTAになります。

スレッドプールはMTAです。STAスレッドでいっぱいだった場合、スレッドがプール内の他のスレッドの1つで作成されたオブジェクトにアクセスしようとすると、それが必要になるため、スレッドプールが不安定になるためです。マーシャリング。

Thread.SetApartmentStateは、定義上、スレッドごとにのみ機能します。(あなたが発見したように)他のスレッドに影響を与えることは決してありません。オブジェクトはアパートに属し、スレッドはシングルスレッドモデルに属する場合があります。スレッドがモデルが一致しないオブジェクトにアクセスしようとすると、マーシャリングする必要があります。

COMサーバーが「両方」としてマークされている場合は、STAまたはMTAスレッドからのプロキシなしで使用できます。その場合は、幸運なことに、最初にMTAスレッドで作成する必要があります(またはスレッドプールスレッドに作成させる必要があります)。

STAスレッドで作成すると、他のすべてのスレッドがSTAであっても(特に)、最初に作成したスレッドからオブジェクトを呼び出さない限り、すべてプロキシを経由します。

COMサーバーがシングルスレッドの場合は、STAスレッドだけでなく、最初に作成したSTAスレッドからも呼び出す必要があります。そうしないと、プロキシを介してマーシャリングされます。

于 2012-10-10T15:27:57.597 に答える