2011-04-28 57 views
4

我有一個難題。我已經「繼承了」一個非常糟糕的設計和非常複雜的系統,我正在逐步進行現代化和重建(和我的團隊一起)。問題在於目前的系統依賴於200多個用戶,並且由於(缺少)設計,他們在性能方面存在重大問題。目前最棘手的問題是大量的工作被放置在UI線程上,導致GUI掛起,直到線程被清除並且消息泵送可以繼續。這些工作中的大部分確實需要在GUI線程上,因爲它正在更新網格中的大量字段,因爲其他線程上的其他計算結果。UI調度緩衝?

問題是:我沒有資源致力於重寫這裏涉及的線程模型和底層類,而且這項工作的複雜性會帶來顯着的風險,這是我的客戶無法接受的。

我想知道是否有人對如何使UI更高性能有任何建議,而不會干擾currnet線程模型。

我最初的想法是,可能有某種方法可以在實際調用UI線程之前放置一個「緩衝區」,以確保GUI不會被重載,或者它確實能夠退出調度到它。

任何建議將不勝感激。

我知道這一切都不是理想的,但我們是我們的地方,我真的希望在爲期一年的重寫完成之前爲我的用戶提供更好的體驗!

謝謝!

更新#1 這是一個winforms應用程序...對不起,這一開始並不清楚。新代碼是WPF,但這些模塊是winforms。

更新#2 我想我可以嘗試改變大多數的BeginInvoke調用UI線程調用,引進了系列化,希望能提高用戶界面的響應。 任何人都可以預見的任何(不明顯的)缺點?

+0

使異步調用同步正在有效地回到單線程方法。調用阻塞調用線程,直到UI線程更新,所以你不會獲得任何東西。 (當然,如果所有invoke調用都來自UI線程,那麼也不會丟失任何東西。) – 2011-05-02 22:02:44

回答

1

我不知道它是否適用於您的特定情況,但過去我曾經處於類似的情況(雖然可能壓力較小),並且我came up with some code讓我元帥或多或少的任意處理從後臺線程到UI線程的代碼。這是寫在WinForms的時代。

這可能會提供一種風險較低的技術,可以將某些計算返回到某些後臺線程,並且可以更容易地將UI更新整理到前臺,而無需完全重構線程模型(或缺少它)。

關於UI的性能,有時使其更快的最佳方式是少做。當我創建鏈接代碼時,我正在處理的應用程序正在解析數百兆字節的字符串以手動嵌入一些xml。用stringbuilders替換不可變的字符串使得OOM失敗情況下的操作在掛鐘時間的5分鐘內完成。然後我注意到,對於它解析的每個元素,它都更新了UI。我調整了代碼以每50個元素更新一次ui,並將其降低到了幾分之一分。關閉所有UI更新將時間縮短爲幾秒鐘。

您是否考慮過不更新UI直到計算完成,也許只是運行進度條?另外一種可能性(不是我的頭頂,不知道它有多邪惡)可能是將更新排列爲一個字典中的lambda表達式,而字典中的控件被更新。這樣,如果單個控件多次更新,您可以將冗餘更新替換爲值。 (假設應用程序沒有直接從UI讀取值來執行計算,當然這可能是::()

+0

好東西greg..this可能會給我一個緩衝區的好起點! – miguel 2011-04-28 20:42:00

0

如果您正在進行大規模更新,您可以暫停並恢復控件中的綁定,使用SuspendBindingResumeBinding方法CurrencyManager。這樣,如果由於大量UI交互而無法在單獨的線程中移動某些內容,則仍然可以通過不顯示更新來獲得某些性能提升。這些更新可能會有所幫助,特別是在使用網格或其他控件時。

+0

我認爲這些都是在基類上的方法:http://msdn.microsoft.com/en-us/library/system.windows.forms.bindingmanagerbase.aspx :) – 2011-04-28 21:27:08

0

假設這是一個WinForms應用程序,一個相當冒險的方法是定期在您的內部調用Application.DoEvents()在UI線程上運行的密集型工作。這允許消息泵在邏輯中處理未決消息。請注意,這是充滿了自己的一套危險,如:

  1. 所有UI事件可以觸發,這意味着你必須有東西像按下按鈕觸發長期運行的UI更新,隨後阻止你以前的UI使用DoEvents()產生的工作。這是一種特別陰險的形式,當你'雙擊'一個按鈕,這會產生一個長操作,產生DoEvents(),它處理另一個按鈕的點擊並旋轉相同的操作,直到完成,然後返回控制返回到操作中間的第一個按鈕點擊處理程序。這意味着您必須非常小心在UI線程的這些「長時間運行」操作期間允許進行哪些UI交互。

  2. 因爲用戶可以與UI進行交互,所以他們可能會使您的代碼先前對事物沒有改變的假設無效。同樣,限制用戶可以做的事情也很重要,以便他們不會使操作依賴的狀態無效。當然,你遇到了另一個線程中運行代碼的相同問題。

  3. 這是VB6時代的一種相當普遍的技術(多線程很難做到),但它在現代開發中被忽略了。它可能會讓您擺脫傳統應用程序中的一個緊張局勢,但我建議使用//HACK標記標記它以便將來清理。

+0

有趣...我喜歡簡單,可能是在進入更復雜的解決方案(也許是對Greg的想法的修改)之前,最好嘗試一下。我有一種感覺,交互會導致它成爲一個非行人。可憐。 – miguel 2011-04-28 20:34:39

+1

這是一個危險的解決方案,恰恰是因爲您可以在幾分鐘內「修復」行爲,但如果您希望它能夠安全地運行,仍然有很多複雜性需要管理。您會遇到與其他更精細的解決方案相同的複雜性,但至少在這些情況下,複雜性會更加明顯。 – 2011-04-28 21:01:43

+0

是的,Application.DoEvents()是危險的業務。應該警告,這可能會導致意外重入,特別是在系統設計不佳的情況下。 – 2011-04-28 21:25:01