当速度太快且需要更新太多数据时,UI无响应

我做了一个控件来记录从不同线程到屏幕的消息。 它使用富文本框来显示格式化文本。

当有20个线程每隔200-250ms追加它们的消息时,主UI在一段时间内变得无响应,并且在处理消息等待之后,UI开始再次响应。 当线程运行时,窗口的移动不平滑。

写入富文本框的消息与锁同步。

您有什么建议可以改善表现? 我打算运行100个线程。


这是我的代码。 我将控制台输出重定向到它,它记录正​​在进行的所有内容并以格式化的forms显示在富文本框中。

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 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(); } 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(); } } } 

让您的工作线程将他们的数据添加到某种队列/列表中,然后让主线程每隔一秒/半秒从新数据存储中添加一批新数据(调整以适应您的过程)。

像这样基本的东西可能会很好:

  public class DataStore{ private object _lock = new object(); private List _data = new List(); public void Add(T data){ lock (_lock){ _data.Add(data); } } public T[] TakeWork(){ T[] result; lock (_lock){ result= _data.ToArray(); _data.Clear(); } return result; } } 

只需创建一个DataStore,让您的工作线程使用Add函数添加要显示的工作然后执行

  foreach (var s in _dataStore.TakeWork()){ richTextBox.AppendText(s); } 

在System.Windows.Forms.Timer事件中。 你可能也希望修剪富文本框文本,但是如果你只是在整天抽取数据,你的应用程序将开始减速….

让他们写入缓冲区RichTextBox(实际上并不是表单的一部分),并且每250毫秒左右只将缓冲区附加到UI RichTextBox。

也许您可以尝试使用线程池或任务来更好地管理线程。