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 属性访问器和方法实际上在创建对象的线程上运行。从而保证线程安全。

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

您通常可以通过在工作线程上创建 COM 对象并将工作线程转换为单线程单元中的工作线程来为它们提供线程安全的家,从而避免这种开销。但是至少有两个原因不起作用,线程池线程始终是 MTA。最终的失败是,这些 EnvDTE 对象不是由您的代码创建的。您可以对前者 (Thread.SetApartmentState) 做一些事情,但不能对后者做一些事情。

于 2013-06-02T20:47:48.097 回答