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