保存.NET用户设置需要很长时间

9
在我们的.NET 4.0 Winforms应用程序中,一些用户(所有Win7 x64)最近在应用程序使用以下代码保存其设置时遇到了非常长的等待时间:
Properties.Settings.Default.Save();
  • 典型持续时间:0.5至1秒
  • 极端持续时间:15至20秒

应用程序设置(范围:用户,所有内容保存在AppData\Local\\下的user.config中)由几个自定义类和两个表示打印机设置的类组成: System.Drawing.Printing.PageSettings 和 System.Drawing.Printing.PrinterSettings

在其中一台机器上使用GlowCode分析器,我发现以下函数需要17秒:

<Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterPrinterSettings_x003A__x003A_Write9_PrinterSettings Nodes="1" Visits="1" percent_in_Child="100.00 %" Time_in_Child="17.456" Time="17.456" Avg._Time_in_Child_="17.456" Avg._Time="17.456" Blocks_net="12" Bytes_net="1024" Blocks_gross="1087" Bytes_gross="494146" />

其中持续时间几乎平均分配给三个获取器(从GlowCode查看器中获取):

  • PrinterSettings::get_PaperSizes
  • PrinterSettings::get_PaperSources
  • PrinterSettings::get_PrinterResolutions

进行一些研究后,发现以下页面: https://social.msdn.microsoft.com/Forums/vstudio/en-US/8fd2132a-63e8-498e-ab27-d95cdb45ba87/printersettings-are-very-slowhttp://www.pcreview.co.uk/forums/papersources-and-papersizes-really-slow-some-systems-t3660593.html,引用:

在某些系统上,特别是Vista x64系统上,如果编译为x64,则枚举printersettings对象的papersources或papersizes集合需要很长时间(5至15秒),如果编译为x86,则需要10-20秒。使用一个小测试应用程序只保存PrinterSettings,在其中一个“慢”的机器上显示了约3.5秒的保存时间,而在另一个机器上则显示了0.2秒的持续时间,这对应于我的快速开发机器。有什么关于原因和如何改进的想法吗?如何找到这些延迟的真正原因?编辑:感谢指出打印机设置是通过驱动程序获取的,这可能解释了某些机器上的延迟。在未来无法访问的机器上更新打印机驱动程序是不可能的。此外,我不会(我知道我知道)仅因为某些人可能会遇到滞后并最终破坏向后兼容性而减少要保存的PrinterSettings信息...也许如果我在后台尝试序列化(在用户进行了一些打印机更改后?)它可能会加速事情...

1
我怀疑PrinterSettings对象必须重新查询打印机的信息,这样会很慢。为什么你要存储PrinterSettings对象?从中获取的数据如果物理打印机发生变化则会改变。最好不要缓存那些信息。 - Joel Lucsy
1
首先,欢迎来到 Stack Overflow!其次,为你的第一个问题点赞!你显然已经做了很多研究,并且进行了文档化。 - Lynn Crumbling
我有一个项目,基本上做的是同样的事情,并且没有问题。现在正在开车去上班,稍后我可以找出它并在今天上午发布。不过它是用vb写的。如果我没记错的话,它涉及使用自定义包装器,以不同的方式序列化每个位。 - pinkfloydx33
@bettwäsh 我有一个答案,但它是用VB.net编写的,而且代码很长。我没有时间运行它通过转换器并测试它是否有效,但如果你需要的话,我可以发布所有类(在VB中)/包装器/序列化程序。这更多是.NET问题,而不仅仅是C#问题。 - pinkfloydx33
2个回答

1

第一个建议:

检索纸张来源和纸张大小的调用被传递给驱动程序。您最好确保安装了最新版本的驱动程序。旧版本的驱动程序(特别是那些随盒子附带的CD中的驱动程序)可能过时且存在漏洞。如果还没有,请访问制造商的网站并获取最新版本。

第二个建议:

除此之外,这会很麻烦,但您可以尝试使用底层的Win32 API而不是CLR对应项。在这种情况下,您将调用GetPrinter,请求PRINTER_INFO_2结构体。一旦您拥有了它,就可以检查pDevMode以获取包含您正在查找的所有信息的DEVMODE结构体。

这个问题这个问题应该会有所帮助。

不要持久化整个PrinterSettings类实例,而是只持久化各自基本类型的设置。保持简单--字符串,整数,布尔等。显然,Serializer正在请求与打印机通信,这就引入了延迟。我敢打赌,如果您抓取单个类成员并自己对它们进行序列化,您将看到改进。

显然,这意味着当您加载设置时,您需要将所有这些设置反序列化回新的PrinterSettings类,并应用它们。

编辑1,响应问题编辑

没错-您可以在后台异步运行Save()。您唯一的问题是,如果用户在保存完成之前尝试结束进程(关闭应用程序),则必须保持一个bool以指示是否正在进行保存(在回调触发时设置为false)。如果用户尝试退出应用程序且bool为true,请放置“请稍候,正在保存设置...”,直到bool变为false。


在我重新阅读了你的问题之后,我现在怀疑我的答案的后半部分是否有任何帮助。听起来好像你无法控制调用请求打印机设置的代码。我仍然建议更新驱动程序。 - Lynn Crumbling
我修改了我的回答并提出了更合适的建议。 - Lynn Crumbling
你可以使用前台线程(Thread.IsBackground = false)并始终显示“正在关闭,请稍候”消息。这样,您就不需要通信线程的状态。 - Conrad Frix

0

看起来,一些机器通过安装的驱动程序查询页面和打印机设置需要很长时间。我找不到更多具体信息。

为了缩短关闭时间,在用户更改打印机设置后,上述设置的部分在后台线程中被分配和保存。这需要大约10秒钟。

在关闭(表单关闭)期间,这些设置不会再次分配,但我们仍然保存所有设置(使用Properties.Settings.Default.Save()),并且序列化程序以某种方式识别出它们没有更改要查询,因此保存非常快:

在0.02至0.05秒之间,但仍然可以正确保存所有设置!

有趣的事实:这个问题是在我们得到新办公室打印机的那周首次报告的 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接