为什么Visual Studio后台线程如此之慢?

时间:2013-06-02 19:48:27

标签: visual-studio-2012 envdte

我正在尝试更新我的扩展程序VSFileNav以使其与VS2012一起使用并对其进行一些改进。它应该列出Visual Studio解决方案中的所有文件,但我也想将它扩展到列出方法/符号。

我以前尝试过这个,但从来没有找到问题的根源。我发现如果我在主线程上枚举Solution->Projects->Project Items它的速度相当快,但是如果我尝试使用任何类型的线程,那么事情就会慢下来。我知道符号搜索需要一段时间才能完成我之前尚未重新实现的尝试,但作为示例,在尝试查找所有ProjectItem文件名时:

  

ProcessMainThread:7毫秒   ProcessBackgroundThreadPool:6661 ms
  ProcessCustomThread:6750 ms

运行此代码的代码片段,正如我已经提到的那样,它最终枚举了所有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长得多,否则我不会太在意......

1 个答案:

答案 0 :(得分:5)

你正在发现那里没有免费午餐的法则。一种经常适用于尝试在大型对象模型中使用线程的法则。与任何大块代码一样,VS自动化对象模型不是线程安全的。并通过COM自动保护安全。这确保您在工作线程上使用的EnvDTE属性访问器和方法实际上在创建该对象的线程上运行。从而确保线程安全。

这涉及很多开销。两个线程上下文切换加上编组方法参数的成本加上编组结果的成本。加上所有者线程响应编组请求的延迟,通常是最大的块和高度可变的,因为它取决于它正在做的其他任何事情。编组呼叫的典型减速与不跨越公寓边界的呼叫是x10000,您的测量结果很接近。

通常通过在工作线程上创建COM对象并在单线程单元中转换工作线程来为它们提供线程安全的主页来避免这种开销。但至少有两个原因是行不通的,线程池线程总是MTA。而最终的垮台,这些EnvDTE对象并非由您的代码创建。您可以对前者(Thread.SetApartmentState)执行某些操作,但不能执行后者操作。