Visual Studio 2013 中异步解决方案负载性能的改进

[原文发表地址] Asynchronous Solution Load Performance Improvements in Visual Studio 2013

[原文发表时间] 2013-10-14

改善解决方案的负载

过去的几年中,Visual Studio 团队一直在努力提高开发大型解决方案的Visual Studio 的性能和可扩展性。你们很多人特别感兴趣的一个领域是我们最初的解决方案的加载时间。对于Visual Studio 2012,我们实现了使大型解决方案异步加载,这将大大提高我们许多用户的加载速度。对于Visual Studio 2013,我们通过将文档选项卡的初始化推迟到文档被需要使用时,来提高解决方案的负载性能。在这篇文章中,我们将帮助你看到在最新版本中期望看到的变化,以及一些我们从使用预发布版本的客户那里看到的早期性能数据。

大负载

在此之前的VS 2012 ,解决方案是所有资源一次性加载。在加载期间,整个 IDE 将被阻挡,直到为解决方案可用而做的所有必要的准备和初始化完成时为止。使用更大的解决方案的用户可能熟悉此对话框:


对于只有几个项目的一个小的解决方案,加载通常不会花太多时间。但随着解决方案的复杂性和大小的增加,加载该解决方案所需的时间也会增长,等待此对话框消失的时间也会增长。所以当使用VS 2012时,我们问过自己,"如果我们只加载用户需要工作的项目,会发生什么?"

去异步

我们的理由是,在任何时候,开发人员只能积极地工作在一个解决方案中的几个项目。当解决方案被关闭时,如果我们能够确定哪些项目对于开发者来说是最重要的,那么我们就可以在下一次解决方案的加载时,先加载这些项目。其余的项目则可以在不影响开发人员的生产效率的某个时间加载。

上述文章描述了异步加载的解决方案,所以我不会在这里详谈了。但对于这个话题,知道的关键概念是,我们用打开的文档,来确定哪些项目应该在下一次解决方案加载时首先被加载。使用“局部性原理”的概念,我们可以推断,如果一个文件打开着,而该解决方案已经关闭,那么它很可能会在解决方案重新开启后不久被再次需要。为了确保解决方案加载之后该文件是处于可用状态,我们必须载入拥有该文档的项目(以及它所依赖的任何项目),以确保编辑和导航按预期方式工作。因为我们用一个模态对话框阻碍了UI,直到加载完成,我们称此为溶解负载的模态阶段。剩余的项目将在稍后的时间中被异步加载,他们将不会影响开发者的生产效率(被称为意料之中异步阶段)。

进度!

我们的内部测试表明:从异步加载的解决方案中获得重大的潜在收益,但最终的问题是在实践中用户得到了多少收益。为了实现此目的,我们添加了新的遥测点,使我们能够分析异步解决方案加载在我们的客户那里的工作性能如何。使用这些遥测点,我们可以计算出发生Visual Studio 2012 更新3上的负载。虽然也可以异步加载单个项目的解决方案,但他们不是这些改进的重点作用对象,所以我们将首先着眼于至少包含2 个项目的加载。



这些数字是很有前途的。我们查看所有解决方案加载的四分之一,我们推迟加载超过解决方案60%的比例,仅阻碍 IDE 2 秒左右。解决方案加载更多时,我们开始看到异步解决方案负载产生的影响开始减少。到75 个百分点时,解决方案加载几乎同步加载整个解决方案并且响应时间大大增加。

尽管只有 2 个项目的解决方案可以受益于异步加载,但我们预期对于更大的解决方案的影响会更明显。例如,当针对具有 10 个或更多的项目的更大的解决方案时,我们可以看到异步加载产生了更大的影响。


到75 个百分点时,项目的延迟加载比例从 0.3%增加到 18%。虽然模态加载时间略有增加,但如果不推迟项目的加载的话,它将会大得多。

虽然这是令人鼓舞的进展,但是我们想知道什么可以进一步增加异步加载的项目的数目。我们再来看我们的遥测,发现了与速度较慢的加载密切相关的变量之一,即会话之间保持打开状态的文档的数目。

看看在这种方式下只有一个项目并且只有一个打开着的文档的加载,这将会导致模式加载项目的数量大大增加。我们仍然的在IDE的响应时间量上看到明显的改善,但显然有进一步改进的余地。

在此基础上,对于VS 2013,我们问自己一个类似的问题:"如果我们只加载用户最有可能使用的文件,将会发生什么?"

变懒。 很好的方式。

作为正常的开发活动 (如编辑 & 调试)的一种结果,往往在解决方案结束时, IDE 中都打开着多个文档。上图表明,随着打开文档的项目数量增加,同步加载的项目数量也会增加。然而,许多这些文件未被正在使用,或者有效地隐藏在其他文件的背后或关闭着的屏幕后面。大多数情况下,在任何给定的时间内,只有较小的文件子集是可见的。这些文件最有可能是在关闭解决方案时开发人员最近使用的,并且最有可能要在下一解决方案加载时第一次使用。

使用同样的逻辑,使我们只能加载解决方案中的前面的重要项目,我们提出的的理由是,如果我们只加载项目的可见文档,那么,我们可以进一步减少不得不同步加载的项目的数目。其余的项目以及不可见的文档会异步加载,正如他们没拥有任何打开的文档一样。只有当需要使一个不可见文件变得可见的事件发生时— — 例如文档选项卡被单击时 — — 我们才会付出加载必要项目的成本。

通过延迟文档的加载我们还发现另外一套节省时间的方法。除可以避免某些项目的加载,我们也注意到我们将有可能推迟加载 IDE 的整个组件。在 IDE 中打开着的每种不同类型的文档都具有一组相应的程序集和数据结构,它们需要被加载并初始化以便正确的呈现该文档 (例如,设计器)。对于任何的这些已经打开的,但当加载该解决方案时却不可见的文档类型,我们现在也避免支付引导那些子系统的花费,直到它们被需要。在某些情况下,不加载这些组件所节省的时间实际上比不加载项目所节省的时间更多 !

他看起来像什么

从外观上看, IDE看起来是一样的。所有之前的会话中打开的文档选项卡的显示与其解决方案被关闭时是完全一样。他们似乎都像以前一样得被加载了。然而,只有完全可见的那些被加载,而其余仍处于未初始化状态,直到需要时。

对于那些需要以编程方式与打开的文档进行交互的扩展程序,他们将继续查找当前正在运行的文档表 (RDT) 中的所有文档。通过 RDT 访问文档的惯用方法已被更新,以确保在返回所需的内容之前,必要的项目已经得加载并且文档已被完全初始化。

关于 VS 扩展程序的最佳做法的说明:

为了帮助确保文档推迟正常工作,充分发挥其潜力,组件加载的延迟和扩展访问真正必要的文档的延迟是很重要。扩展可以检查下列新的属性来检测文档在延迟的状态并且等待直到与它们进行交互之前完全加载:

IVsWindowFrame,请检查VSFPROPID_PendingInitialization.

对于本机代码与运行的文档表工作,检查正在从IVsRunningDocumentTable.GetDocumentInfo()返回的 RDT_PendingInitialization.

对于托管代码,使用IVsRunningDocumentTable4.GetDocumentFlags()来检查有相同的标志.

当初始化延迟的文档时,将由IVsRunningDocTableEvents3.OnAfterAttributeChangeEx宣布的RDTA_DocumentInitialized属性.

继续深入

基于我们的原型,我们是很有信心延迟非可见文件的初始化,对于减少许多解决方案加载的时间,会有很大的帮助。但接下来的问题是何时加载这些被延迟的文档。经过讨论后我们获得了两种可能性: 要么在解决方案加载结束时以异步方式加载,要么按需加载。

第一种方法是一个我们都熟悉的,因为我们和异步加载项目使用相同的策略。在解决方案加载期间,一些项目和文件暂时处于未初始化状态,但最终一切都达到所预期的, IDE 的大多数组件都处于完全加载的状态。

然而,我们发现在某些特定情况下,在解决方案加载完成后,异步地初始化文件会导致一些非常重大的响应问题。请谨记,在此时IDE处于交互的状态,我们期待开发人员能够将积极致力于他们的解决方案。对想要完成工作的人来说,在 UI 中任何明显的延迟都可能是非常恼人的中断。而我们看到的许多文件可以正常进行初始化而不会造成明显的 UI 挂起现象,但另外一些比较复杂的文档则会出现这种状况。具体而言,当第一次我们试图初始化一些设计器或非常大的文件时,由于整个组件被第一次加载并初始化,我们可能会遇到非常明显的延迟。从用户的角度看,这可能是出乎意料的,并且不发出任何警告。这一定不是良好的用户体验。所以我们选择第二个选项,仅加载所需求的文档。使用此模型,只需花费加载他们极其需要的文档的时间。

早期的结果

使用一些我们的内部基准解决方案,我们已经能够说明,推迟文档初始化可以为甚至只有少量打开着的文件的加载带来多大的改善 (在此例中为 5)。  

当然,如果从用户使用文档推迟的实际成绩来看,将会更有趣。为了看到这一点,我们可以看看那些支持在项目中推迟文档初始化的一些初始预览版和发布候选版中的遥测结果:  

从这一数据,我们可以初步阐明:延缓文档初始化是如何影响实际用户的解决方案负载的。到目前为止,我们看到在一个解决方案中约四分之一的项目和超过一半的打开的文件在同步加载时被推迟。并且这些延期的项目是除了那些已经被异步加载的项目之外的!

除了一般的平均值,我们也看到一些出色的加载真正的证明了延迟文档的初始化是非常有用的:  


 

结论

在 Visual Studio 2012中 ,我们针对提高解决方案在 IDE 中的加载性能,采取了重要的第一步。我们通过推迟文档的初始化,采取了第二个步骤来减少加载解决方案的等待时间,并使用户比以前更早的启动使用。

除了说明下一版本中的新功能,我们希望这篇文章能告诉您当我们计划未来功能和改进现有功能时,遥测和您的反馈意见是多么的重要。我们会继续分析从客户体验改善计划中得到的数据以及从其他可用渠道提供反馈意见,来评估解决方案加载质量。所以请利用 RC 版本,让我们通过连接,用户之声,VS中的发送-A-微笑系统,或在下面评论等方式来了解您的心声!

 

 

 

 

 

 

i