2

拡張機能VSFileNavを更新して、VS2012で動作するようにし、いくつかの改善を加えようとしています。Visual Studio ソリューション内のすべてのファイルを一覧表示することになっていますが、これを拡張してメソッド/シンボルも一覧表示したいと考えています。

私はこれを以前に試しましたが、問題の根底に到達することはありませんでした。私が見つけたのはSolution->Projects->Project Items、メインスレッドで列挙するとかなり速いですが、何らかの種類のスレッドを使用しようとすると、処理が遅くなるということです。まだ再実装していない以前の試みからシンボル検索に時間がかかることは知っていますが、例として、すべてのProjectItemファイル名を見つけようとする場合:

ProcessMainThread にかかった時間: 7 ミリ秒
ProcessBackgroundThreadPool にかかった時間: 6661 ミリ秒
ProcessCustomThread にかかった時間: 6750 ミリ秒

これを実行するための私のコードのスニペットProjectItems

public void TimeProcess()
{
    Stopwatch sw = Stopwatch.StartNew();

    ProcessMainThread();
    sw.Stop();
    Debug.WriteLine("ProcessMainThread took : " + sw.ElapsedMilliseconds + " ms");

    ProcessBackgroundThreadPool();

    ProcessCustomThread();
}

public void ProcessMainThread() 
{
    Process(); 
}

public void ProcessBackgroundThreadPool()
{
    System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback((o) => 
    {
        Stopwatch sw = Stopwatch.StartNew();
        Process();
        sw.Stop();
        Debug.WriteLine("ProcessBackgroundThreadPool took : " + sw.ElapsedMilliseconds + " ms");
    }));
}
public void ProcessCustomThread() 
{
    System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(() =>
    {
        Stopwatch sw = Stopwatch.StartNew();
        Process();
        sw.Stop();
        Debug.WriteLine("ProcessCustomThread took : " + sw.ElapsedMilliseconds + " ms");
    }));
    t.Start();
}

だから私の質問は、一体なぜスレッドでほぼ 1000 倍の時間がかかるのですか? また、実行が遅くならないノンブロッキング関数を作成するにはどうすればよいでしょうか? -ファイル内のシンボルの列挙を開始すると、7msよりもはるかに長くなることに注意してください。そうでなければ、あまり気にしません...

4

1 に答える 1

5

あなたは無料のランチはありませんという法則を発見しています。ラージ オブジェクト モデルでスレッドを使用しようとする場合によく適用される法則。コードの大きな塊と同様に、VS オートメーション オブジェクト モデルはスレッドセーフではありません。また、VS 自動化の基盤である COM によって安全に保たれます。これにより、ワーカー スレッドで使用する EnvDTE プロパティ アクセサーとメソッドが、オブジェクトを作成したスレッドで実際に実行されるようになります。したがって、スレッドセーフが保証されます。

これには大量のオーバーヘッドが伴います。2 つのスレッド コンテキスト スイッチに加えて、メソッド引数をマーシャリングするコストと、結果をマーシャリングして戻すコスト。加えて、マーシャリング要求に応答する所有者スレッドのレイテンシーは、通常、最大のチャンクであり、それが何をしているかに依存するため、大きく変動します。マーシャリングされた呼び出しとアパートメントの境界を越えない呼び出しの典型的な速度低下は x10000 であり、あなたの測定値は近いです。

通常、ワーカー スレッドで COM オブジェクトを作成し、シングル スレッド アパートメントでワーカー スレッドを切り替えて、スレッド セーフなホームを提供することにより、この種のオーバーヘッドを回避します。しかし、うまくいかない理由が少なくとも 2 つあります。スレッドプール スレッドは常に MTA です。そして究極の落とし穴は、これらの EnvDTE オブジェクトがあなたのコードによって作成されたものではないということです。前者 (Thread.SetApartmentState) については何かできますが、後者についてはできません。

于 2013-06-02T20:47:48.097 に答える