2011-04-21 97 views
4

我们正在处理WinForm应用程序的慢启动(这是一个大型应用程序,并且有许多控制程序集)。控件组件是DevComponents。 Ngen被应用于防止jit编译,但是加载时间略微减少。立即显示启动画面

该应用程序具有启动画面,但仅在应用程序启动后的12秒内出现。有没有办法一次显示启动画面?

我们目前的建议是创建一个轻量级的应用程序与启动画面,运行主应用程序在一个单独的进程,并关闭轻量级应用程序时主应用程序的初始化完成。

+0

如果NGEN优化不显着,我建议放弃它并保留所有JIT的好处。 – 2011-04-21 11:34:20

+1

你如何显示启动画面?你能提供一个代码示例吗? – 2011-04-21 11:37:21

+0

它通过使用一个单独的表单实现。 – 2011-04-21 11:45:19

回答

10

你永远不会得到一个.NET应用程序的启动画面,以立即显示 即使您已经使用程序集来消除JIT编译时间,仍然必须等待所有.NET Framework DLL都加载到内存中。这是一个非常大的框架,并且需要花费不少的时间来加载冷启动。没有什么可以真正做到的。

微软试图尽可能地缓解痛苦。 WindowsFormsApplicationBase class(它在Microsoft.VisualBasic命名空间中定义,但不要让它吓跑你;它完全可以从C#应用程序中使用)提供了用于显示启动画面的内置机制。您只需将其SplashScreen property设置为适当的形式,其他所有内容均在幕后处理。即使在冷启动的情况下,它的响应时间也经过了极大的优化,但它仍然不会成为。

您唯一的选择是在非托管代码中编写小包装,其唯一目的是尽快抛出初始屏幕,然后调用.NET应用程序开始启动自身。当然,这里的打火机越好越好。 C++是一个选项,但C可能是更好的选择。您需要最大限度地减少必须链接的外部库的数量,因此像MFC或Qt这样的框架绝对是不可用的:您需要直接定位Windows API。

在Visual Studio团队做类似的事情在2010年VS他们的过程available on their blog的一个非常有趣的解释:

即使Visual Studio 2010中使用WPF其主窗口,使用WPF的启动画面将需要我们等待CLR和WPF初始化,然后才能在屏幕上绘制单个像素。尽管我们在.Net 4.0中对CLR和WPF启动速度做了一些巨大的改进,但仍然不能完全匹配原始Win32的性能。因此,我们选择了原生C++代码和Win32作为启动画面。

但我不会在这里花太多时间。由于您通常应该给用户启用和关闭启动屏幕的选项,并且大多数用户会选择关闭启动屏幕,因此很多人不太可能首先看到它。任何好的优化分析器都会告诉你,这不值得优化。

1

我想说的去与你目前的建议。除非它已经完全加载到内存中,并且由于需要时间,我建议有一个加载器应用程序,它显示启动并执行主要的巨大应用程序(作为子进程)。

在巨大的应用程序中,加载时终止父应用程序。顺便说一下,这不会杀死孩子。

+0

一个小型的WinForms应用程序不太可能会比一个* Large * WinForms应用程序加载表单的速度快得多。这个想法是在任何一种情况下加载闪屏形式* first *,而不是以显示主窗体开始,并且主窗体显示闪屏。 – 2011-04-21 11:41:36

+0

咦?除了CLR之外,没有任何依赖项的小型WinForms应用程序的加载速度将显着高于具有大量依赖项的应用程序。你是什​​么意思“从显示主窗体开始,主窗体显示启动画面”?你能详细说明吗? – 2011-04-23 08:25:11

+1

请读我的评论给Jason Moore的回答。只有在需要时,CLR才会加载依赖关系。除非实际使用这些外部程序集中的代码,否则不会受到任何处罚,无论它们是否由您的应用程序引用。我的意思是,你可以显示一个简单的启动画面窗体,它不依赖于Main方法开始时的任何外部依赖,并且它将在空的WinForms应用程序中加载,就像它将一个一百个依赖。这些依赖不会被加载,直到你请求它们,这就是JIT编译的魔力。 – 2011-04-23 08:27:37

0

我过去所做的快速和肮脏的方式是有两个应用程序,您的主应用程序和您的splashscreen应用程序。主应用程序对于所有重量级的DLL,控件等都是正常的。splashscreen应用程序仅仅是一个应用程序和一个Windows窗体,其中所有不必要的引用DLL都从项目中剥离出来 - 实际上,您可以更进一步,请使用轻量级的.NET框架,如紧凑的.NET框架或早期版本的.NET框架(如1.X或2.0)。

你会做的是让启动画面应用程序启动并立即显示单个启动画面。有一个Windows窗体计时器(设置为100毫秒),并启用计时器作为窗体的Load事件的最后一行。当定时器触发时,禁用定时器,然后启动您的真实应用程序。如何做到这一点见this discussion。现在主应用程序将开始启动。一旦应用程序完成初始化并可能加载第一个表单,然后让主应用程序终止启动屏幕应用程序。有关杀死应用程序的更多信息here

+0

目前还不清楚这如何改善情况。即使您有一个相对较小的.NET应用程序,您仍然必须等待.NET DLL和CLR加载。更重要的是,CLR足够聪明,不会加载你不使用的程序集/被引用的DLL。如果您的启动画面表单不使用这些参考DLL中定义的任何控件,并且它是您在屏幕上投掷出的第一个东西,那么它在“大”应用程序中的速度与在“小” 。 – 2011-04-21 12:02:42

+0

此外,我非常建议放弃使用计时器的建议。用户不希望等待*更长的时间*为您的应用程序加载,只是因为您向他们展示广告牌。我并不反对启动加载时间非常长的应用程序,但延迟添加(即使只有100毫秒)是完全没有意义的,这几乎是无礼的。 – 2011-04-21 12:03:47

+0

我的观点是,splashscreen应用程序不必引用原始帖子中提到的任何大型DevComponents dll。那并且瞄准一个更小。NET框架将使其更快。我假设只有主应用程序需要引用(并因此加载)所有在12秒或更长时间内使原始程序加载的DevComponents dll。 – 2011-04-21 12:18:56

5

对于用C++编写且使用本机Windows API的轻量级可重用启动画面组件,请参阅Stefan Olson's splash screen。它采用了Cody Gray所暗示的方法,从单独的非CLR流程开始,然后加载主CLR应用程序。

我不得不在我上一份工作中实现完全一样的东西,我可以确认这种方法效果很好 - 用户单击开始菜单中的程序图标和出现的初始屏幕之间的时间仅为几毫秒,所以感觉'即时'。

+0

您可能会考虑总结您帖子中的链接内容 – FabienAndre 2012-10-30 17:00:43