一直想要写一点东西,把自己在工作中遇到的东西分享给大家,无奈水平有限,每每想写的时候,就感觉写的东西太过浮浅,同样的东西不如其它人写的有水平,假若自己再写出来可能会给其它人带来困惑,加上自己语言组织能力不行,就懒得写了,由于这两天在分析UI刷新的性能问题,而今天也终于分析出性能损耗点,按捺不住心中的高兴,因此就想在这里给大家分享一下方法。
Dispatcher Queue性能分析
我相信,学习过WPF人都会知道不能直接通过其它线程访问UI控件,原因是由地Windows操作系统使用的单线程的,基于消息处理的用户界面,一次只能有一个线程访问用户界面,与任何轮换线程的交互都必须通过Windows消息泵来封送。而其它线程要访问怎么办,那只能通过消息封送了,常用的代码如Dispatcher.BeginInvoke或Dispatcher.Invoke。封送到UI线程进行处理。在控件与后台逻辑频繁交互的项目中的,这样的封送代码可能是相当的多,而对于界面数据加载慢这样的问题,一一去查这些封送代码显然是相当的不现实,那怎么办?
其实,在我们封送消息到UI线程时,封送的消息会以FIFO逐一进行处理,当然其还是一个优先级的概念需要理解。对于这样的一个队列,我们可以跟踪加载到队列每个任务的开始及结束时间,即可知道性能耗费点,便可再跟据相关代码进行进一步的分析。
DispatcherInactive |
在调度程序没有要处理的其他操作时发生。 |
OperationAborted |
中止操作时发生。 |
OperationCompleted |
完成操作时发生。 |
OperationPosted |
将操作发布到调度程序时发生。 |
OperationPriorityChanged |
在更改操作的优先级时发生。 |
OperationStarted |
调用操作时发生。 |
我们可以对Dispatcher.Hooks进行上面这些事件的附加即可知道每个任务的进度,详细可研究Msdn。添加到Dispatcher Queue中的每个任务都用一个DispatcherOperation来表示,这个类型有一个Name属性,可以用来标识具体是什么样的任务,由于这个属性是internal类型的,所以获取时需要进行反射获取,代码简单如下:
PropertyInfo pro = typeof(DispatcherOperation).GetProperty("Name", BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.NonPublic);
打印出每个任务的Name属性,就可以进一步分析性能了。
由于添加到Dispatcher Queue中的任务是相当的多,如UI渲染,Input事件等,可以把相关的任务都打印到txt中,然后搜索自己程序中的命名空间,即可找到自己程序添加相关任务,使用NotePad++, 相当好用。
Ending!!!