2011-04-15 92 views
2

我做了一個控制,將來自不同線程的消息記錄到屏幕上。它使用富文本框來顯示格式化文本。當響應太快,需要更新的數據太多時

當有20個線程,其附加他們的消息每200-250ms主UI成爲響應一段時間和等待被處理的用戶界面中的消息後,再次開始響應。當線程運行時,窗口的移動並不平滑。

信息寫入到豐富的文本框與鎖同步。

什麼你可以建議以提高性能?我打算運行100個線程。


這是我的代碼。我將控制檯輸出重定向到它,它會記錄正在發生的所有事情,並以格式化的形式顯示在富文本框中。

public void RedirectStandardOutput() 
     { 
      Console.SetOut(ConsoleStream); 

      System.Diagnostics.Debug.Listeners.Add(new System.Diagnostics.TextWriterTraceListener(Console.Out)); 
      System.Diagnostics.Debug.AutoFlush = true; 
     } 

控制檯重定向後,所有Console.WriteLine(「bla bla」);被寫入屏幕。


using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using CoreLib.Parsers; 

namespace ConsoleWidget 
{ 
    public class ConsoleStream : System.IO.TextWriter 
    { 
     private readonly object _textBoxLock = new object(); 

     public RichTextBox TextBox { get; set; } 
     public List<TextFormat> TextFormatList { get; set; } 

     public bool AutoClear { get; set; } 
     public int AutoClearLength { get; set; } 
     public bool AutoSave { get; set; } 
     public string AutoSaveDir { get; set; } 


     public ConsoleStream() 
     { 
      TextFormatList = new List<TextFormat>(); 
     } 

     public void AppendText(string text) 
     { 
      if (TextBox == null) return; 

      var textLength = TextBox.TextLength; 

      if (AutoClear && textLength > AutoClearLength) 
      { 
       if (AutoSave) 
       { 
        var dir = string.Format(@"{0}\{1}\{2}", Environment.CurrentDirectory, AutoSaveDir, CoreLib.Extensions.DateTimeExtensions.DateTimeNowDir); 

        if (!System.IO.Directory.Exists(dir)) 
         System.IO.Directory.CreateDirectory(dir); 

        var path = string.Format(@"{0}\{1}.log", dir, CoreLib.Extensions.DateTimeExtensions.GetDateTimeNowFileName); 

        TextBox.SaveFile(path); 
       } 

       TextBox.Clear(); 
      } 

      TextBox.AppendText(text); 

      // Format text. 
      foreach (var textFormat in TextFormatList) 
      { 
       int beginIndex; 
       int length; 

       if (textFormat.GetFormatProperties(text, out beginIndex, out length)) 
       { 
        // RichTextBox counts newline "\r\n" which is double char as single char. 
        // Causes shifting in selection starts. The lines below count the "\r" chars before the beginIndex. 
        var leftText = text.Substring(0, beginIndex); 
        var newLineCount = leftText.Count(c => c == '\r'); 

        TextBox.SelectionStart = textLength + beginIndex - newLineCount; 
        TextBox.SelectionLength = length; 
        if (!textFormat.Color.IsEmpty) 
         TextBox.SelectionColor = textFormat.Color; 
        if (textFormat.Font != null) 
         TextBox.SelectionFont = textFormat.Font; 
       } 
      } 

      TextBox.ScrollToCaret(); 
     } 

     public void Clear() 
     { 
      lock (_textBoxLock) 
      { 
       TextBox.Clear(); 
      } 
     } 

     public int TextLength 
     { 
      get 
      { 
       lock (_textBoxLock) 
       { 
        return TextBox.TextLength; 
       } 
      } 
     } 

     public void SaveAs(string path) 
     { 
      lock (_textBoxLock) 
      { 
       TextBox.SaveFile(path); 
      } 
     } 

     public override Encoding Encoding 
     { 
      get { return Encoding.Default; } 
     } 

     public override void Write(string value) 
     { 
      if (TextBox == null) return; 

      var action = (Action)(() => AppendText(value)); 

      lock (_textBoxLock) 
      { 
       if (TextBox.InvokeRequired) 
        TextBox.BeginInvoke(action); 
       else 
        action(); 
      } 
     } 

     public override void WriteLine() 
     { 
      Write(NewLine); 
     } 

     public override void WriteLine(string value) 
     { 
      Write(value); 
      WriteLine(); 
     } 
    } 
} 
+1

您能分享更新文本框的代碼嗎? – 2011-04-15 14:14:40

+1

你是怎麼做跨線程寫作?您是使用Control.Invoke,Control.BeginInvoke,還是在UI線程上輪詢消息? – 2011-04-15 14:15:12

+0

您可能還想考慮使用除富文本框以外的其他內容來顯示數據。我從來沒有使用過,所以我只是猜測,但我懷疑隨着TextBox文本大小的增加,添加文本會變得越來越慢。只是一個想法.... – 2011-04-15 14:54:42

回答

5

讓你的工作線程的數據添加到某種隊列/列表,然後讓主線程的新數據存儲中的每個秒/半秒增加一批新的數據(調以滿足您的過程)。

一些基本的東西像這可能將是罰款:

public class DataStore<T>{ 
    private object _lock = new object(); 
    private List<T> _data = new List<T>(); 
    public void Add(T data){ 
     lock (_lock){ 
      _data.Add(data); 
     } 
    } 

    public T[] TakeWork(){ 
     T[] result; 
     lock (_lock){ 
      result= _data.ToArray(); 
      _data.Clear(); 
     } 
     return result; 
    } 
} 

只需創建一個數據存儲,讓你的工作線程使用Add功能添加的工作則顯示做

 foreach (var s in _dataStore.TakeWork()){ 
      richTextBox.AppendText(s);     
     } 
在System.Windows.Forms.Timer事件中的

。您可能還想修剪富文本框文本,因爲如果您只是整天不停地抽取數據,您的應用程序就會開始變慢......

5

讓他們寫一個緩衝區RichTextBox的(一個實際上並不是你的表格的一部分),只有緩衝追加到UI RichTextBox的每250個毫秒左右。

0

也許你可以試試線程池或任務,而不是管理你的線程更好。