我正在尝试更新我的扩展程序 VSFileNav使其与VS2012兼容并对其进行一些改进。它应该列出 Visual Studio 解决方案中的所有文件,但我也想将其扩展为列出方法/符号。
我以前曾尝试过此操作,但从未深入了解我的问题。我发现,如果我在主线程上枚举 Solution->Projects->Project Items
,速度相当快,但是如果我尝试使用任何类型的线程,速度就会减慢。我知道符号搜索需要一段时间,从我之前的尝试来看,我还没有重新实现,但作为一个例子,当尝试查找所有 ProjectItem
文件名时:
ProcessMainThread took : 7 ms
ProcessBackgroundThreadPool took : 6661 ms
ProcessCustomThread took : 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 倍,以及如何生成一个不会运行缓慢的非阻塞函数? - 请记住,当我开始枚举文件中的符号时,它将比 7 毫秒长得多,否则我不会太在意...
最佳答案
您正在发现“天下没有免费的午餐”的法则。经常适用于尝试在大型对象模型中使用线程的法则。与任何大块代码一样,VS 自动化对象模型不是线程安全的。并由 VS 自动化的基础 COM 保证安全。这可确保您在工作线程上使用的 EnvDTE 属性访问器和方法实际上在创建该对象的线程上运行。从而保证线程安全。
这涉及大量的开销。两次线程上下文切换加上编码(marshal)方法参数的成本加上编码(marshal)结果的成本。再加上所有者线程响应编码请求的延迟,通常是最大的 block 并且高度可变,因为它取决于它正在执行的其他操作。编码调用与不跨越公寓边界的调用相比,典型的速度减慢为 x10000,您的测量结果很接近。
通常,您可以通过在工作线程上创建 COM 对象并将工作线程转换为单线程单元来为它们提供一个线程安全的家,从而避免这种开销。但至少有两个原因不起作用,线程池线程始终是 MTA。最终的失败是,这些 EnvDTE 对象不是由您的代码创建的。您可以对前者做一些事情(Thread.SetApartmentState),但不能对后者做一些事情。
关于visual-studio-2012 - 为什么 Visual Studio 后台线程如此慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16886654/