2012-03-16 175 views
1

這裏的問題有點抽象。我們都知道,爲後臺線程更新一些UI元素。從多個後臺線程更新UI

Dispatcher.Invoke() 

是唯一的選擇(是嗎?)。但是,Dispatcher.Invoke()本身將更新任務委託給UI線程。考慮以下場景:

  • 後臺線程經常更新UI。
  • 數十個線程更新相同的用戶界面。

Dispatcher對象會繼續將更新任務委託給UI線程,並且UI線程可能會變慢。什麼是可能的解決方案?我們如何解決Windows Forms中的這個問題,其中線程模型與WPF非常相似? WPF是否提供了其他線程技術?

問候,

回答

1

首先爲什麼需要更新頻繁出現人眼不會注意到的UI,理想情況下,即使任何進度更新了一秒鐘的間隔,也是可以接受的。例如,如果您正在編寫一個文件,並且您可能每30毫秒寫入4K字節,人眼就不會注意到,我們也不會在乎屏幕上的性能(以毫秒爲單位)

不僅您將使UI線程忙,而且分派器。調用也會阻塞你的其他線程直到執行完成後,Dispatcher.BeginInvoke將不會阻塞您的其他線程。

如果UI線程只是在屏幕上更新少量標籤或進度,它可能會在幾毫秒內完成更新。

WPF和任何其他平臺都不能提供任何更好的方式,因爲UI非常複雜,並且允許從多個線程訪問可能導致死鎖,因此應用程序可能會變得無法響應。這就是每個平臺的原因,無論是java,objective-c還是任何UI框架,都需要您僅在UI的創建者線程中更新UI。

但是,WPF中還有一種方法可以在每個窗口中創建多個UI線程,但它也相當複雜。遊戲等使用了一種稱爲雙緩衝的東西,在後臺使用單獨的線程處理一個緩衝區,而前一個緩衝區仍在屏幕上更新。

+0

感謝您的回覆。 「但是,WPF中也有一種方法可以在每個窗口中創建多個UI線程,但它也相當複雜。」我瞭解所提供的所有風險,這可能是我正在尋找的解決方案。 我從http://eprystupa.wordpress.com/2008/07/28/running-wpf-application-with-multiple-ui-threads/ 開始您可以發佈一個更好的鏈接來開始使用這個概念嗎? 謝謝。 :) – James 2012-03-16 10:48:47

2

如果您通過發佈消息,超載的GUI線程輸入隊列(APC的,代表,等等),速度比他們可以處理,那麼就會出現問題,不管WPF /表格/不管。

在那些情況下,其中多個GUI狀態被如此頻繁更新的發佈的每一個變化都會超載隊列和/或導致改變太快是人類可讀的顯示器,是很常見的非GUI線程存儲他們在共享對象中的最新數據以及GUI線程以更合理的間隔使用定時器顯示數據。

如果所有數據必須在不損失的情況下顯示的,(例如,一個GUI備忘錄或HTML呈現器必須顯示發送的所有內容)經由對象池和/或數據的懶惰張貼,則合適的流程控制,可能需要防止消息隊列超載。

'這裏的問題有點抽象' - 不是那麼抽象。我在忙碌的應用程序中多次遇到此問題。在我的東西中,長時間的輸入隊列過載往往會導致死鎖,因爲我的線程間通信池中的所有對象都卡在張貼的消息中,因爲GUI被阻塞而無法處理並釋放到池中 - 嘗試獲取對象從空池開始:((

+0

其實,你應該用Invoke確定。它的BeginInvoke往往阻塞隊列。 – 2012-03-16 10:20:25

1

簡單,不要使用Invoke來更新UI。相反,讓工作線程將需要「發送到UI線程」的數據發佈到像隊列或列表這樣的共享數據結構中,並讓UI線程在特定時間間隔內進行輪詢。這有幾個優點。

  • 它打破了Invoke強加的UI和工作線程之間的緊密耦合。
  • 用戶界面線程可以在UI控件更新時指示它......當你真的想到它時應該這樣做。
  • 如果在工作線程中使用InvokeBeginInvoke,則不會有超出UI消息隊列或消除其他消息的風險。
  • 工作線程不必等待來自UI線程的響應,就像Invoke那樣。
  • 您可以在UI和工作線程上獲得更高的吞吐量。
  • InvokeBeginInvoke是昂貴的操作。

我知道我一直在關注這個,但在很多情況下,Invoke真的有更好的選擇。諸如Invoke之類的編組技術是方式過度使用。