2017-03-15 42 views
0

我的應用程序使用了很多線程,每個線程都使用我的AddDetailLog函數在全局文本框中添加線程的進度,所以我可以按照每個線程的進度進行操作。這個函數每秒可以調用500次以上,當我使用VS2015 Profiler時,我已經看到使用我的CPU的50%是這個函數。當我加載超過150線程時,我的CPU達到100%,所以我真的需要優化這個功能。優化調用日誌功能 - 多線程

多線程優化的功能:

public void AddDetailLog(string text) 
    { 
     if(Program.SHOWDETAILSLOG) 
     { 
      if (this.textBox_log.InvokeRequired) 
      { 
       SetTextCallback d = new SetTextCallback(AddDetailLog); 
       this.Invoke(d, new object[] { text }); 
      } 
      else 
       this.textBox_log.AppendText("[" + DateTime.Now.ToString("HH:mm:ss") + "] - " + text + Environment.NewLine); 
     } 
    } 

,因爲多線程的事情,我需要檢查,如果我的textBox需要一個調用,因爲所有的線程(不是BackgroundWorker的)的作用在相同的textBox在我的全球形式。

如果有人有任何想法來優化這個功能,我會很高興聽到它。

感謝

+2

你可以創建一個緩衝區來存儲消息(不顯示它們),然後有一個計時器每隔1秒觸發一次以將其附加到「TextBox」....或問自己,「我是否需要看到所有這些日誌消息?「 –

回答

3

首先,Control.Invoke()阻塞調用過程,最終擊敗你的後臺線程的目的,因爲他們最終會通過GDI消息泵同步。您可以使用BeginInvoke()而不是異步進行呼叫,從而允許您的後臺進程繼續。

其次,寫入這樣的速度一個TextBox控制是要你慢下來,因爲任何改變TextBox.Text必火TextChanged,其中除其他事項外將重繪與更新的文本控制。每秒執行500次,特別是使用任何自定義TextChanged處理程序(如代碼將文本框滾動到底部),並且您將會燒焦UI線程非常脆。

相反,爲什麼不讓記錄器將條目寫入更簡單的內存對象,然後在您的表單上執行Timer以檢索,連接並在TextBox控件中顯示這些消息?考慮到高併發性,我建議使用ConcurrentQueue<string>。您的後臺工作人員執行「TryAdd」調用以排入日誌條目,然後您的UI Timer.Tick處理程序使用TryTake將它們出列,並以更友好的方式將它們附加到TextBox(例如,可能會在連接10個批次之前連接條目,然後再附加到文本框)。

最後,TextBox的內容越長,渲染的時間就越長,因爲TextBox必須計算字符串的顯示大小才能呈現滾動條並顯示應該實際顯示的字符串部分。在30k個字符左右之後,我會截斷日誌顯示的「後端」。爲避免丟失潛在有價值的信息,同一處理程序可將消息傳遞給StreamWriter,將所有內容寫入文件;您可以在此處添加另一個級別的異步處理以保持UI的響應。