1.什么时候用到invoke和beginInvoke
--当调度线程不是主线程的时候
2.invoke和beginInvoke效率差别
测试方法:使用线程更新图片内容,此时,调度线程和非调度线程不是同一个,要用到封送处理(invoke或beginInvoke)
Task.Factory.StartNew(() => { while (true) { Capture(); } });
这时候同时更新100张图片,也就是一个方法里,调用100次invoke或者beginInvoke方法:
2.1使用dispatcher.invoke(Action action)
效果图
这时候我们可以看到:dispatcher.invoke(Action)会造成(界面卡顿、鼠标卡顿、丢帧、但是图像跟视频同步没有延迟)
2.2 使用dispatcher.beginInvoke(action)
效果图
这个时候我们会看到Dispatcher.beginInvoke(Action)会造成(界面卡顿、鼠标卡顿、图像跟视频严重延迟,但是不丢帧)
2.3使用dispatcher.invoke(action,dispatcherPriority.Background)
效果图
这时候我们可以看到:dispatcher.invoke(Action,dispatcherPriority.background)会造成(丢帧、但是图像跟视频同步没有延迟、鼠标不卡顿、界面流畅)
2.4 使用dispatcher.BeginInvoke(action,dispatcherPriority.Background)
效果图
这时候我们可以看到:dispatcher.BeginInvoke(Action,dispatcherPriority.background)会造成(鼠标不卡顿、界面流畅、不丢帧、但是延迟严重)
3.结论
当我们把测试结果汇总成表格的时候,我们就能发现一些现象.
世界并不是完美的,每个方式都有各自的优势和缺陷。我们应该根据需要把握那中间的一个点,或者说是一个度来衡量到底用哪种方式。
使用方式效果 | 界面鼠标流畅与否 | 图像同步还是延迟 | 丢帧情况 |
Invoke(action) | 卡 | 同步 | 丢帧 |
BeginInvoke(action) | 卡 | 不同步 | 不丢帧 |
Invoke(action,background) | 流畅 | 同步 | 丢帧 |
BeginInvoke(action,background) | 流畅 | 不同步 | 不丢帧 |
结论1:在大量调用封送invoke的过程中,invoke会造成:丢帧,同步
结论2:在大量调用封送beginInvoke的过程中,beginInvoke会造成:不同步,不丢帧
结论3:在大量调用封送过程的时候,加DispatcherPriority会让界面流畅,不加会卡顿
因此每个人可以根据自己的情况来选择用哪一种封送方式及选择适当的参数。
例如1:在做视频项目的时候,打架关注的是视频的实时性,而略微的丢帧是没问题的。所以用invoke方法比较好。
例如2:在做数据处理的项目中,如果关注数据的完整性,即使不同步是能够接收的。这时候使用beginInvoke比较好。
例如3:当界面封送对象少的时候,或者需要同步数据的时候,即使等待也是可以接收的。不加background。
例如4:当界面封送对象多的时候,需要更加流畅的操作的时候,加background
4.但是世界也是完美的。卡顿、延迟、不流畅等,这类事情的本质原因是加载过多的元素,造成封送数量过大,只要我们把数量降下来就一切流畅了。
我们可以使用【数据虚拟化技术,dataVirtulization】、定向加载、动态数据加载、异步加载等方式来更好地控制程序。
下面就是通过使用动态加载数据的方式,让界面变得更加丝滑流畅。
大致代码如下,也就是只加载视野内的两张图,降低了封送数量,提高了程序效率。
if (i<_index||i>_index+2) { continue; }
效果图:
当然也有更优的办法,比如截图效率提升、图片解码效率等提升了,也会大大提高程序效率及特性。
源码下载:
https://files.cnblogs.com/files/chlm/Dispatcher%E6%B5%8B%E8%AF%95%E6%95%88%E7%8E%87.rar