Visual Studio 2012中,改进的工具箱可快速响应
[原文发表地址] Improved Toolbox Performance Delivers Highly Responsive Visual Studio 2012
[原文发表时间] 2012-07-16 14:00
正如在上一篇有关键入和编辑性能的帖子中所述,我们会跟进一个帖子,它是关于Visual Studio 2012中工具箱的增强功能。我想要介绍来自Visual Studio两个小组的成员Duke Kamstra和Chuck England,他们会向你描述我们为提高工具箱的响应而所做的工作。
Visual Studio充满了非常棒的速成应用程序的开发功能。有时获取所有这些强大的功能是有代价的。使用Intellisense、红色波浪线、智能重命名、重构等等需要大量的工作。随着功能变得更加灵活,以及解决方案的规模和复杂度的增加,我们已经发现额外的工作量可能会导致UI变得反应迟缓,重画,甚至挂起。在Visual Studio 2012中,我们想要改善这方面的用户体验。在今天的博客帖子中,我们会讨论其中一个功能,工具箱以及我们已经所作的性能提升。
为什么要专注于工具箱?
在之前关于性能的博客帖子中,我们提到了PerfWaston。工具箱就是其中之一的功能,它产生大量的点击次数。有了这个数据,我们设计了几种测试场景。我们使用客户提供的以及我们创建的解决方案来模拟大型复杂的解决方案,以此来配置这些场景。
我们通过分析性能追踪学会了几件事情:
- 看似与工具箱交互无关的场景其实受到刷新工具箱逻辑的影响。例如,当我们关闭一个大型的解决方案时,我们观察到工具箱阻断了30秒Visual Studio的用户界面。
- 影响可能存在细微的不同,这取决于正在使用的设计器。
- 较大的解决方案似乎有更大的改善潜力。
- 设计器的执行影响着工具箱的性能。这意味着这不是简单地重构一个单独的类,或调整工具箱内的一些主要例程,我们还需要调整设计器自身。
工具箱如何工作?
为了帮助解释我们做了哪些改变来改善工具箱的性能,首先描述工具箱是如何工作的会大有帮助。在一个高层次,工具箱与设计器一起筛选出一个所有已知的可视化组件的列表,此列表是与加载的设计器有关的。所以比如说,如果您在使用Windows Forms设计器,你会看见Windows Forms控件。当你在使用WPF设计器时,你就会看到WPF控件。
这份列表是从两个不同类型的可视化组件中建立的。首先,有一些在机器上注册的项目。这些项目是由Visual Studio提供的或者是用户从第三方供应商安装的。工具箱给这些组件建立缓存列表,并让设计器能读取这些列表。然后设计器根据它的需要筛选合适的组件。
其次,有一些在用户项目中定义的用户组件。这些都是自定义组件,例如,您自己定义的用户控件,数据集等。对于这些组件,设计器自己会负责在解决方案的生成结果中查找,并将它们添加到工具箱中。
这两种类型之间的较大区别在于,注册组件是静态的,很少改变,而用户的组件可能会改变,因为你会经常更新您的解决方案中的代码。
对于用户组件,基本的发现过程包括迭代(通过所有解决方案的生成结果)来找出设计器中可用的潜在的控件。这是通过反射般的过程找到控件的。我们通过我们的性能跟踪了解到,用户控件的“发现”对于您的解决方案的规模和复杂度来说是相对花费巨大的。
我们专注于什么?
虽然产品中大多数设计器在更新用户组件列表时,一般机制是相似的,但是必须专门研究每个设计器来了解提升性能的机会。虽然在产品中有很多的设计器(如Workflow,UML modeling,DSL(Domain Specific Languages),WCF, DataSet), 大部分是基于三个共同的基本实现(WinForms, WebForms, 和WPF/XAML)。对于其中每一个基本实现,我们发现最大的性能机会存在于当用户执行下列操作之一:
- 载入一个解决方案
- 打开一个设计器
- 改变生成设置(Debug/Release)
- 生成一个解决方案
- 关闭一个解决方案
为了提高在这些情况下的性能,我们遵循了几个基本原则。
不做我们不需要的工作
我们遵循的首要原则是停止做我们不必要做的工作。这似乎不言而喻,但生活很少那么简单。只是因为你在一个时间点建立了一个简单和可行的设计,并不意味着它会永远保持原样。这就是性能调整是必需的地方了。
工具箱中的一个这种情况是选择执行工作的时间。如果你同时打开了一个设计器和一个工具箱,然后,我们假定你想让工具箱和设计界面交互。所以,我们要确保工具箱中所有的可视化组件都是最新的和相关的。
但如果你没有打开设计器呢?如果你打开了设计器,但工具箱窗口是关闭的呢?在这些情况下,我们发现我们依然能确保工具箱保持最新。作为我们调整工作的结果,我们已经消除了这项工作,直到我们看到你有一个打开的设计器,并且工具箱是可见的。
另一个调整的机会是在设计器的代码中发现的,它确保工具箱是始终保持最新。在设计器搜索了新的或改变过的可视化组建之后,工具箱窗口会被更新并显示结果。在Visual Studio 2010中,几个设计器完成这项工作,通过删除原有的一切然后加入大量新发现的项目来实现的。在很多情况下,项目可能完全没有太大的改变。我们的分析表明,这是非常低效的,并且需要相当多的工作和UI重画。为了提高这个部分,我们
只添加或删除工具箱中自上次更新以来更改的可视化组件。
远离 UI线程
我们遵循的第二条原则是从UI线程中删除工作。当在UI线程上长时间运行工作时,Visual Studio无法响应来自操作系统的消息来重画窗口或处理用户的输入,如点击鼠标或键入。在后台线程上异步发生地对比工作并不阻止UI线程处理消息。这是我们如何确保反应灵敏的用户界面的。
性能跟踪发现几起工具箱事件,它们是发生在UI线程上的。一个例子是,由设计器在解决方案中查找自定义组件。
结果
在我们应用了这些原则以后,我们做了一些在工具箱和设计器一起打开的情况下相同的场景下的前后对比。下面的图表展示了我们基于所有的调整和有针对性的性能改变后的性能提升,这些是我们在Visual Studio2012的处理过程中所做的。(是的,这是超过之前%的收益。)
请注意,这些数字是针对一套内部基准解决方案。不同的解决方案可能会看到不同的结果。这些测试用例的典型误差幅度为+/-5%。
Scenario
WinForms
WebForms
WPF/XAML
Load Solution with Toolbox and Designer Open
80%
89%
81%
Load Solution with Toolbox Open
32%
18%
34%
Open Designer with Toolbox Open
66%
93%
35%
Change Build Configuration with Toolbox Open
92%
54%
44%
Rebuild with Toolbox Open
10%
3%
-3%
Incremental build with Toolbox Open
7%
37%
42%
Close Solution with Toolbox Open
28%
16%
26%
还记得我提到过的,在Visual Studio中关闭一个大型的解决方案会产生~30秒的延迟?在测试过程中,我们的调整将这个时间减少到了~700ms。
但是数字仅仅是故事的一部分。要看到有多大的影响,你真的需要亲眼见证。你可以看一看这里的最新预发布版Visual Studio 2012。对于你们之中曾经使用过RC版本的人,请在评论区随意分享你们对它整体性能的印象,在我们的UserVoice网站,或者你可以用Visual Studio 11 Feedback工具发送新的问题报告给我们。如果您经常使用大量的自定义组件,在Visual Studio 2012中,你会发现,它的响应速度更快,并且你几乎可以立即开始工作。
Chuck England –项目经理,Visual Studio组
简短介绍:Chuck England 是一个项目经理,他目前致力于Visual Studio中的核心结构和性能相关的改进。他之前帮助运营Project System和 MSBuild,这些运行在Visual Studio2010/ .NET 4.0中,和即将发布的Visual Studio 2012/.NET 4.5 中。Chuck在开发上有超过30年的经验,在2008年加入微软之前,他在不同的软件行业从事工程师和开发人员。
Duke Kamstra – 高级项目经理,Visual Studio组
简短介绍:Duke在微软已经工作了8年,致力于Visual Studio的不同部分已有5年。他目前的工作是在Visual Studio产品生产线上监督性能提升。
我们希望这些以及我们在Visual Studio 2012 RC版上做的其他改进能提供给你更多收益,并且让你的开发体验更加美妙。请继续用您的反馈和建议帮助我们提高!我非常感谢你们花时间来阅读和评论这些帖子,一如既往地我感谢你们对于Visual Studio的支持。
非常感谢
Larry Sullivan
工程总监