2012-03-22 80 views
2

我的應用程序嚴重依賴線程來處理超大型數據的複雜處理。隨着處理完成,UI需要更新。我知道並嘗試使用BackgroundWorker'sOnProgressChangedRunWorkerCompleted方法來更新UI。還使用UI線程的Invoke方法進行更新。在Win XP 32位和64位操作系統上似乎一切正常。在Win Vista和Win 7(32和64位)上,通過使用Invoke方法更新UI時,應用程序會隨機掛起。從C#中的線程更新UI的其他方法

Invoke的行爲在不同的Win OS上有變化嗎? 除Invoke之外,還有哪些更新線程的UI的方法?

感謝

+0

我的假設是,在不同的操作系統和環境中,更新UI只是需要更長的時間。 – RQDQ 2012-03-22 15:21:36

+1

我不認爲這個問題是新的操作系統 - 我的猜測是,新機器只是更快/有更多的核心(所以併發問題可能會更早到達),或者你只是幸運 - 無論如何:沒有代碼我不' t認爲我們可以幫你 – Carsten 2012-03-22 15:21:52

+1

應用程序不響應,或不刷新本身? – 2012-03-22 15:30:30

回答

2

Invoke的行爲在不同的Win OS上有變化嗎?

它應該不,不。但是,線程問題可能以非常不可預測的方式實現。有可能你有一個未知的問題。

除了Invoke之外,從線程更新UI的其他方法是什麼?

使用InvokeBeginInvoke被過度使用,特別是在嘗試向UI線程報告簡單進度信息時。如果您搜索一些與該主題相關的答案,您將會看到我一直在使用這種方法。並且有很好的理由,因爲它們使用這種技術有很多缺點。不幸的是,BackgroundWorker僅通過其ProgressChanged事件使用此機制來更新UI。

另一種方法是讓您的工作線程將進度信息發佈到共享變量中,並讓UI線程通過定時器定期輪詢它。以下是我通常談論的一些關於通過編組技術證明這種方法的論點。

  • InvokeBeginInvoke是昂貴的操作。
  • UI線程可以決定更新表單及其控件的時間和頻率。
  • 它消除了UI和工作線程之間的緊密耦合,這些線程與ISynchronizeInvoke強加。
  • 使用一堆編組操作,沒有超出UI或使UI消息隊列飽和的風險。
  • 您可以在工作線程上獲得更多吞吐量,因爲它不必等待響應,就像Invoke那樣。
+0

我可以保證這種方法。我已經編寫了一個應用程序,每秒接收100次更新。 (通過中間件)嘗試顯示每個人和每個人都是荒謬的,所以我使用上面概述的方法。結果是一個更有用的用戶界面。 – Fen 2012-03-22 16:26:28

1

你可以嘗試使用Invoke()或的BeginInvoke()重載需要Dispatcher.Priority枚舉作爲參數之一。如果您選擇了諸如「背景」之類的參數,您應該會看到您的應用程序仍然響應。唯一的問題就是確保您在不增加隊列的情況下以適當的速率爲您的傳入數據提供服務。

2

不確定發生了什麼問題,但您可以始終運行一個可以定期更新GUI的System.Windows.Forms.Timer;使用一些成員變量在線程之間傳遞原始數據,如果需要的話鎖定內部。不是最優雅的解決方案,但它可能會給你一個不同的看法,因爲線程更加獨立,而不是依賴於主線程的後臺線程。

+1

+1:相反...輪詢進度信息往往*更優雅。 – 2012-03-22 16:01:33

0

另一種選擇是完全放棄多線程。如果您的長時間運行可以分解爲塊,請在GUI線程中執行此操作,並在要更新GUI時使用Application.DoEvents()

我以前不喜歡使用該方法,因爲它不僅可以更新GUI,還可以開始響應用戶輸入,啓動定時器等,但最終它不會比使用後臺線程安全, GUI隨時開始做任何事情。所以可能在每次撥打Application.DoEvents()後,您需要檢查_canceled或其他什麼。 (我最終決定不喜歡這種方法的存在,因爲它消除了線性執行順序的保證,而不是使用它)。

當然,你會失去多核支持,所以如果你想同時運行大量的後臺操作,它會影響性能。